Description

chex4j is a framework for documenting and enforcing the pre- and post-conditions of method calls. Inspired by contract4j it is intended to enforce a light weight form of Design By Contract (Dbc) TM.

To use chex4j you add @Contract, @Pre and @Post conditions to methods within your classes and interfaces:

	@Contract
	public class SimplePublicBankAccount {

		@Post("amount.doubleValue() >= 0.0d")
		public SimplePublicBankAccount(BigDecimal amount ){
			this.balance = amount;
		}
		
		@Post("$_.doubleValue() >= 0.0d")
		public BigDecimal getBalance() {
			return this.balance;
		}

		... // other members
	
	}

Alternatively you can leave the annotation value propery blank and chex4j will automatically resolve and invoke a $Pre or $Post method as the chex:

	@Contract
	public class SimplePublicBankAccount {

		@Pre(message="Negative deposit.") // invokes deposit$Pre(amount)
		@Post(message="Balance exceeds 25k.") // invokes deposit$Post(amount)
		public BigDecimal deposit(BigDecimal amount) {
			this.balance = this.balance.add(amount);
			return this.balance;
		}
		
		@SuppressWarnings("unused")
		private boolean deposit$Pre(BigDecimal amount){
			return amount.doubleValue() >= 0.0d;
		}
		
		@SuppressWarnings("unused")
		private boolean deposit$Post(BigDecimal amount){
			return this.balance.doubleValue() <= 25000;
		}
	
		... // other members
	
	}

When you enable the chex4j javaagent within your IDE or test server the value attribute of the annotations (the "chex") will be compiled into java bytecode using the jboss javassist framework and injected into the body of the method. Should the boolean chex expression return false an assertion error will be thrown detailing the chex that failed - this reflects the fact that it is a programmatic error to violate the constraint.

Chex4j has an offline mode where it can be used to transform classes as part of your build.

The annotations (know as "chex") act as additional documentation about your code. If you annotate methods on an interface then any class which implements your interface the chex will compiled and injected into it at class load time. This will work even if it is 3rd party code where you do not have access to the source code.

The syntax of the injected code can be any valid Javassist code which evaluates to a boolean e.g. "$_" is the value returned by the method:

whatever Any valid java code. Javassist appears to reverse engineer the source code of the class and method body.
$0, $1, $2, ... Actual parameters by position (typically just use the method argument name not the argument position)
$args An array of parameters. The type of $args is Object[].
$$ All actual parameters. For example, m($$) is equivalent to m($1,$2,...)
$cflow(...) cflow variable
$r The result type. It is used in a cast expression.
$w The wrapper type. It is used in a cast expression.
$_ The resulting value
$sig An array of java.lang.Class objects representing the formal parameter types.
$type A java.lang.Class object representing the formal result type.
$class A java.lang.Class object representing the class currently edited.

see the javassit documentation

Running It - Online Mode

chex4j has a javaagent which instruments classes at load time using the JBoss Javaassist toolkit. This means that Javassist has to be loadable when your classes are loaded to run in 'online mode'.

The correct version of Javassit to use is named within the chex4j pom.xml this can be made accessible to the chex4j javaagent with a JVM argument such as following (note the "/a:" is not a drive letter it is the jvm flag meaning "append to boot classpath"):

		-Xbootclasspath/a:/some/path/to/javassist-3.14.0-GA.jar

The chex4j javaagent is then run from within the chex4j jar file with a VM flag such as:

		-javaagent:target/chex4j-core-1.0.1.jar=net.sf.chex4j...,chex4j.test...,dir=target/chex4j

where after the '=' is a comma separated list of package names for the javaagent to byte code instrument. Note that you must add the "..." to each package name which is the same syntax as the standard JVM -ea flag. The optional 'dir=' flag is the location to dump out the instrumented class files.

Take a look at the embedded ant task within the chex4j-test/ant-run-time-chex4j.xml to see an example of using ant to fork a jvm enabling the javaagent as documented above.

Running It - Offline Mode

The javaagent is very useful when running your junit tests particular within an IDE as it will be immediate. If you want to deploy the code with the chex enabled you may wish to use the ChexOfflineMain class as part of your build. Take a look at the ant example in chex4j-test/ant-compile-time-chex4j.xml

Getting It

If you are building with maven then add the following dependency:

		<dependency>
			<groupId>net.sf.chex4j</groupId>
			<artifactId>chex4j-core</artifactId>
			<version>1.0.2</version>
			<scope>compile</scope>
		</dependency>

You can also download it from https://sourceforge.net/projects/chex4j

Building It

On the commandline a build using maven2.2.1 looks like:

		mvn install

Note that because it is a javaagent the test cases are in a separate subproject which forks a jvm to set the javaagent vm setting. This means that you will notice that mvn outputs that it is skipping tests but you will also see output of JUnit4.7 text test runner actually running the tests that are launched using the maven-ant-plugin within the chex4j-test project.