|
External class contract example
There are two ways to attach a contract to a class, an "internal" way and an "external" way.
The following example uses the external way,
i.e. the contract class refers to its target class
by using the C4J Annotation @Contract and extending the target class.
package timeofday;
public class TimeOfDay {
public static final int HOUR_MIN = 0;
public static final int HOUR_MAX = 23;
public static final int MINUTE_MIN = 0;
public static final int MINUTE_MAX = 59;
public static final int SECOND_MIN = 0;
public static final int SECOND_MAX = 59;
private int hour;
private int minute;
private int second;
public TimeOfDay(int hour, int minute, int second) {
setHour(hour);
setMinute(minute);
setSecond(second);
}
public void setHour(int hour) {
this.hour = hour;
}
public void setMinute(int minute) {
this.minute = minute;
}
public void setSecond(int second) {
this.second = second;
}
public int getHour() {
return hour;
}
public int getMinute() {
return minute;
}
public int getSecond() {
return second;
}
}
The corresponding contract class TimeOfDayContract extends TimeOfDay and looks like this (complete listing):
package timeofday;
import static de.vksi.c4j.Condition.ignored;
import static de.vksi.c4j.Condition.postCondition;
import static de.vksi.c4j.Condition.preCondition;
import static de.vksi.c4j.Condition.unchanged;
import de.vksi.c4j.ClassInvariant;
import de.vksi.c4j.Contract;
import de.vksi.c4j.PureTarget;
import de.vksi.c4j.Target;
@Contract(forTarget = TimeOfDay.class)
public class TimeOfDayContract extends TimeOfDay {
@Target
private TimeOfDay target;
@ClassInvariant
public void classInvariant() {
assert target.getHour() >= HOUR_MIN : "hour >= HOUR_MIN";
assert target.getHour() <= HOUR_MAX : "hour <= HOUR_MAX";
assert target.getMinute() >= MINUTE_MIN : "minute >= MINUTE_MIN";
assert target.getMinute() <= MINUTE_MAX : "minute <= MINUTE_MAX";
assert target.getSecond() >= SECOND_MIN : "second >= SECOND_MIN";
assert target.getSecond() <= SECOND_MAX : "second <= SECOND_MAX";
}
public TimeOfDayContract(int hour, int minute, int second) {
super(hour, minute, second);
if (preCondition()) {
assert hour >= HOUR_MIN : "hour >= HOUR_MIN";
assert hour <= HOUR_MAX : "hour <= HOUR_MAX";
assert minute >= MINUTE_MIN : "minute >= MINUTE_MIN";
assert minute <= MINUTE_MAX : "minute <= MINUTE_MAX";
assert second >= SECOND_MIN : "second >= SECOND_MIN";
assert second <= SECOND_MAX : "second <= SECOND_MAX";
}
if (postCondition()) {
assert target.getHour() == hour : "hour set";
assert target.getMinute() == minute : "minute set";
assert target.getSecond() == second : "second set";
}
}
@Override
public void setHour(int hour) {
if (preCondition()) {
assert hour >= HOUR_MIN : "hour >= HOUR_MIN";
assert hour <= HOUR_MAX : "hour <= HOUR_MAX";
}
if (postCondition()) {
assert target.getHour() == hour : "hour set";
assert unchanged(target.getMinute()) : "minute unchanged";
assert unchanged(target.getSecond()) : "second unchanged";
}
}
@Override
public void setMinute(int minute) {
if (preCondition()) {
assert minute >= MINUTE_MIN : "minute >= MINUTE_MIN";
assert minute <= MINUTE_MAX : "minute <= MINUTE_MAX";
}
if (postCondition()) {
assert unchanged(target.getHour()) : "hour unchanged";
assert target.getMinute() == minute : "minute set";
assert unchanged(target.getSecond()) : "second unchanged";
}
}
@Override
public void setSecond(int second) {
if (preCondition()) {
assert second >= SECOND_MIN : "second >= SECOND_MIN";
assert second <= SECOND_MAX : "second <= SECOND_MAX";
}
if (postCondition()) {
assert unchanged(target.getHour()) : "hour unchanged";
assert unchanged(target.getMinute()) : "minute unchanged";
assert target.getSecond() == second : "second set";
}
}
@Override
@PureTarget
public int getHour() {
return ignored();
}
@Override
@PureTarget
public int getMinute() {
return ignored();
}
@Override
@PureTarget
public int getSecond() {
return ignored();
}
}
Please note that external contracts need a special configuration of C4J which is explained in the section Configuration. |