An annotation processor to update your persistence.xml during javac
When Java Persistence API is used in a managed environment (like Java EE container), there is often a deployment step and a notion of deployable module (an ear/war/jar) that represents the boundary of an application. During deployment container/persistence provider can discover managed persistence classes by introspecting .class files bundled in the application. But when Java Persistence API is used in Java SE environment, there is no such predefined deployment step, nor is there any deployable module. So a persistence provider does not know what are all the classes to introspect. Hence the spec requires users to specify the list of managed persistence classes in persistence.xml. A managed persistence class is a class that is either an Entity or Embeddable or EmbeddableSuperclass.
In this article, I shall show how to write an Annotation Processor that can be used along with J2SE's Annotation Processing Tool to automatically generate the list of managed persistence classes and update persistence.xml during compilation of entity source code. In the process I will also show how to use JAXB to read and write XML. I suggest you read this if you are not familiar with apt. The complete source code along with a build script is available here. There is also a README that tells you how to build and use the tool.
Overview of the source code:
1. AnnotationProcessorFactory: ListPersistenceClassApf.java
This is the entry point. It implements AnnotationProcessorFactory interface.
2. AnnotationProcessor: ListPersistenceClassAp.java
This is the real annotation processor. It implements AnnotationProcessor interface. ListPersistenceClassApf instantiates this class and hands over the declarations for annotation processing.
3. service provider configuration file: META-INF/services/com.sun.mirror.apt.AnnotationProcessorFactory
apt is a generic tool that comes with Sun's JDK. It does not know about our custom annotation processor factory. So it has to be told about our annotation processor factory. It can be done in a couple of ways: passing -factory option while invoking apt or by using service provider configuration file. I am using the later approach.
4. Marshalling and unmarshalling of persistence.xml XMLReaderWriter.java
As you can see from this source code, I am using JAXB 2.0 RI to read and write persistence.xml. The reason I use JAXB is because it generates the code that is responsible for reading and writing XML from a given schema. See the gen-src target in build.xml to see how we generate code using JAXB. Also take a look at the binding.xjb
if you are interested to know how to control code generation.
The reason I use glassfish is because it implements Java EE 5 spec, which means both Java Persistence API 1.0 as well as JAXB 2.0.
How to use?
export GLASSFISH_HOME="Wherever you have installed glassfish"
apt -d samples/classes/ -classpath $GLASSFISH_HOME/lib/javaee.jar:$GLASSFISH_HOME/lib/appserv-ws.jar:`pwd`/build/apt.jar -Add=samples/persistence.xml samples/src/sahoo/*.java
See the above command is invoked just like you invoke javac to compile a set of java sources available in samples/src/sahoo/ dir and you directing the compiler to produce the classes in samples/classes dir.
In fact it does what ever javac does + more.
The only non-javac option used here is -Add which is used by our
annotation processor to know the input persistence.xml file location.
The above command picks up Java sources from samples/src dir and
persistence.xml from samples dir. It produces the new persistence.xml
in samples/classes/META-INF dir. It produces the classes in samples/build
directory.By the way, the good news is JAXB 2.0 is part of Java EE 5 and Java SE 6 which is being implemented in mustang.
Comments are most welcome.