Name | Modified | Size | Downloads / Week |
---|---|---|---|
Parent folder | |||
chex4j-core-1.0.0-RC2-sources.jar | 2010-09-12 | 19.2 kB | |
chex4j-core-1.0.0-RC2.jar | 2010-09-12 | 30.1 kB | |
README.txt | 2010-09-12 | 9.3 kB | |
Totals: 3 Items | 58.6 kB | 0 |
Copyright 2010 Simon Massey. All rights reserved. net.sf.chex4j is licensed under the terms of the Eclipse Public License v1.0, as defined by the attached file LICENSE-ECLIPSE.txt. Simon Massey (simon at my full name ( no punctuation ) dot org). 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 form of Design By Contract. Activated through configuration you may choose to only use it during unit testing or on test servers with little or no overhead. To use chex4j you add @Contract, @Pre and @Post conditions to methods within your classes and interfaces: @Contract public class SimplePublicBankAccount { ... // other members @Post(message = "Initial balance should be greater than or equal to zero.", value = "amount.doubleValue() >= 0.0d") public SimplePublicBankAccount(BigDecimal amount ){ this.balance = amount; } @Post(message = "Balance should be greater than zero.", value = "$_.doubleValue() >= 0.0d") public BigDecimal getBalance() { return this.balance; } } 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. Optionally the altered class files can be output to disk. These can then be packaged up and deployed to be run without the need of the chex jvm javaagent. Chex4j also has an offline mode where it can be used to transform classes as part of a 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 http://www.csg.is.titech.ac.jp/~chiba/javassist/tutorial/tutorial2.html#before Alternatively you can leave the value of annotations blank and chex4j will automatically resolve and invoke a $Pre or $Post method as the chex: @Contract public class SimplePublicBankAccount { ... // other members @Pre(message="cannot deposit a negative amount") // will resolve and invoke deposit$Pre(amount) @Post(message="cannot have a balance greater than 25k") // will resolve and invoke 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; } } 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 project 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.11.0.GA.jar The chex4j javaagent is be run from within the chex4j jar file with a VM flag such as: -javaagent:target/chex4j-core-1.0.0.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 where to dump out the instrumented class files in case you want to package and deploy those to a test server. Take a look at the embedded ant task to see chex4j-test/ant-run-time-chex4j.xml 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 at chex4j-test/ant-compile-time-chex4j.xml Building It: On the commandline a build 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. To Do List (some or all before a release): * Tested on Sun jdk1.5, 1.6 and 1.7 should perhaps test with IBM JVM and JRockit JVM. * Write up junit/testNJ how-to for eclipse, netbeans and intelliJ. * Try it with a container or two (tomcat and jetty). Release Notes: 1.0.0-RC2 Implemented David Gargiulo feature request to have a convention where the code for the chex can be a regular method in the class. A @Pre or a @Post which does not have a value will look to invoke methodName$Pre or methodName$Post as the chex logic; where methodName is the name of the method which carries the annotation. 1.0.0-RC1 Release Candidate 1. Fixed missing Hamcrest jar on forked jvm chex-test. 1.0.0-FL20100815 Finally settled on a strategy for junit testing the javaagent: moved the tests into a different project 'chex4j-test' as the main classes in that project. The test project has skip-tests true but then forks a jvm with ant which runs activates the javaagent and invokes junit test runner on a test suite. 1.0.0-FL20100221 Have refactored to create OfflineClassTransformer to do build time class transformations. 1.0.0-FL20100221 Broken out the main code into a module below a superpom and have added the beginnings of maven plugin. The plugin is there to launch a new JVM with the chex4j javaagent enabled during the course of the build. For test builds throwing an AssertionEror might be a bit too strong. The Assert class now looks for -Dnet.sf.chex4j.internal.Assert.DONT_THROW_ERROR=true and will only complain to System.err if it finds that entry. 1.0.0-FL20100216 Added ant build script (mostly generated with "mvn ant:ant") with a target test-instrumented-classes which forks java and runs the instrumented classes within junit. Added skip tests 'true' to the maven surefile plug-in configuration. Added an option to dump out the instrumented class files using an optional dir= option to the javaagent: -javaagent:target/chex4j-1.0.0-FL20100216.jar=net.sf.chex4j...,chex4j.test...,dir=target/chex4j This should allow for packaging up the instrumented classes to run on a test server. May also be a good route into ant integration. 1.0.0-FL20100214 For features see the JUnit tests under src/test/java. @Pre and @Post seem to work on constructors, public class methods, package protected methods, interface methods and in abstract class hierarchies. Works with linux jre1.5.0_21, jdk1.6.0_16 and jdk1.7.0_b83 as well as windows jre1.6. To use this library you must specify the following VM argument: -javaagent:path/to/chex4j-1.0.0-FL20100214.jar=com.x.y...,com.a.b... where com.x.y and com.a.b are the package name of the classes that you wish to instrument. You must add three full stops to the end of them to match the syntax of the standard JVM -ea option. "mvn test" does not run the tests successfully as the javaagent is not being applied. Eclipse junit runner works fine with the javaagent flag. This is likely to be classworlds/plexus classloader stuff. I will take a look at alternative ways to fork the tests. Enjoy, Simon