Code Generation solves a lot of problems. And everybody uses it all the day: Ever generated Getters/Setters using your IDE? Or method stubs? Or constructors?
And sometimes complete classes are generated. One famous example is Hibernate that is able to generate Java classes from a database schema.
Most of the projects I have seen so far use a templating engine (FreeMarker or Velocity) to create the source files. Hibernate switched from Velocity to FreeMarker some years ago…
This approach is quite good for simple cases. Those can be solved quite fast using that approach.
Complexity
But things get worse, if you have to generate more sophisticated code. Of course FreeMarker supports conditions and you can do quite amazing things using complex model classes. On the other hand those templates start to get really complicated and hard to debug over time.
And of course you always have two sources: The template file and your data model.
Imports
One thing special to Java source files are the imports. When you conditionally use a class somewhere, you also have to add the import statement conditionally… Nothing that can be solved easily using FreeMarker.
So sometimes one might wish to have a nice API that does all the dirty work for you…
The alternative: Codemodel
I have looked around to find such an API. And it took me quite a long time to find one.
And that API is quite near beside you. Just a little bit hidden.
JAXB has a sub project called codemodel. This is an API that allows you to create Java classes by just using an API…
How to use Codemodel
There is no separate jar for codemodel. But the classes are shipped with every JAXB installation. So since JDK 1.6 the classes are just here and waiting to be used. But since they have renamed the package as “internal” I suggest to import the JAXB jar manually:
For Maven users this should be enough:
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-xjc</artifactId>
<version>2.2.1</version>
</dependency>
A quick introduction
The API is not perfect yet. And it is not documented very well. But it is nearly complete and I didn’t miss much.
Here is a short example that should give you a fast start:
JCodeModel codeModel = new JCodeModel();
JDefinedClass foo = codeModel._class( "a.b.c.Foo" ); //Creates a new class
JMethod method = foo.method( JMod.PUBLIC, Void.TYPE, "doFoo" ); //Adds a method to the class
method.body()._return( JExpr.lit( 42 ) ); //the return statement
The code can be written to the file system. But it can also be written to a single output stream. This is great for testing:
ByteArrayOutputStream out = new ByteArrayOutputStream();
codeModel.build( new SingleStreamCodeWriter( out ) );
This code outputs that code:
-----------------------------------a.b.c.Foo.java-----------------------------------
package a.b.c;
public class Foo {
public void doFoo() {
return 42;
}
}
Great, isn’t it?