Posted by ss141213
on November 26, 2007 at 7:54 AM PST
Java Persistence API specification requires its users to not only provide a persistence.xml file but also enumerate managed persistence class names in that file. In this article, I talk about a Java compiler plugin that can create the persistence.xml file for you automatically during normal course of Java code compilation and show how easy it is to use in your existing build scripts - be it maven or ant or shell script.
I am glad to say that in most cases, I do not write a persistence.xml file any more. No, I am not using any IDE to generate it for me, nor has the spec relaxed any requirement. We will discuss some other time why persistence.xml is a necessary evil. Then what has changed? Well, my compiler creates it for me - yes, I said javac creates it for me. When I execute
javac -d . -classpath ... FooEntity.java BarEntity.java Main.java
, a META-INF/persistence.xml file with necessary entries is created next to my .class file. See an example
of such a generated file. If there already exists a persistence.xml, then the above command just updates the managed persistence class names in it. It does not matter whether javac is invoked from command line, or Ant or Maven. To a certain extent, I can even control what goes into that file. e.g. I can choose the provider name, and it generates appropriate entries specific to the provider. Similarly I can also specify what should be the persistence-unit name and so on. Interested? You can use it. Read on...
No, I have not modified javac. Starting with Java SE 6, the Java Compiler allows users to plug in an annotation processor which gets called in an appropriate phase of compilation. If an annotation processor is available in javac's classpath, then javac can discover it using service discovery mechanism . Read Annotation Processing in javac for further information. Using the said feature, I have written a simple, standard compliant javac plugin to provide the necessary functionality.
How you can use?
You can download the plugin from here
; it is free, comes with no warranty. I will try to support it as time permits. To use it, just add thet jar file to classpath during compilation. That's it, now go onto compile your code as usual. Being a compiler plugin, it is not even required at runtime. Even if it's there in runtime classpath, it is harmless. So, the easiest option is to copy the jar to $JAVA_HOME/lib/ext. Since lib/ext is used in runtime as well, no matter how harmless the jar is, some people don't like this approach. More over, in a shared system, you may not even have permission to write to lib/ext. In such a case, you can follow one of the following options:
For command line javac invocation, just add it to compiler classpath using -classpath option. e.g.,
javac -classpath $HOME/pxml-javac-plugin.jar:$CLASSPATH *.java
Ant users can modify the classpath attribute of the javac task. IDE users can add the plugin.jar in their project's compilation classpath.
Step 1: Download the special maven2 repository format zip file from here
Step 2: Install it in your local maven2 repository (by default ~/.m2/repository) by running following command:
unzip -d ~/.m2/repository pxml-javac-plugin-maven.zip
Step 3: Modify your pom to add a compile time dependency to this plugin like this:
< groupId> org.sanjeebsahoo</groupId>
< artifactId> pxml-javac-plugin</artifactId>
< version> 1.0-SNAPSHOT</version>
< scope> compile</scope>
That's it, no other change is needed. Isn't it straight forward to use?
How to pass additional options to the plugin:
Sometimes you may like to pass additional options to our plugin to control what goes inside the persistence.xml. Currently supported options are described below. Unless specified, all options are optional. Since there can be multiple plugins for the javac, in order reduce probability of name collision, each option is prefixed with "pxmlplugin."
1. pxmlplugin.provider: Acceptable values are toplink, hibernate, openjpa. Default value is toplink. Use this option when you don't have a persistence.xml file to start with and you want the provider to be other than toplink.
2. pxmlplugin.pu: name of the persistence-unit. Default value is pu1. It solves two purpose, viz:
a) when a new persistence.xml is created, this will be used as the name of the persistence-unit.
b) when there already exists a persistence.xml with multiple persistence-units, this is used to select the desired one for update.
3. pxmlplugin.verbose: prints additional information as debugging aid. By default, it is switched off.
How you specify the option depends on which javac you are using. While using javac that comes with Sun JDK, prefix the option by -A. e.g.,
javac -Apxmlplugin.provider=hibernate -Apxmlplugin.pu=pu1 -Apxmlplugin.verbose -classpath pxml-javac-plugin-1.0-SNAPSHOT.jar Foo.java
For non-Sun JDK, check your javac documentation.
I find this plugin very useful. It not only saves me from writing persistence.xml file in most of the case, it allows me to avoid duplicating class names in persistence.xml, thus saves me from troubles that can arise because of duplication of information. Would love to know your comments. Suggest improvements. I will be happy to make it when I get the time. Since the plugin uses all the standard APIs, I expect it to work with all Java SE 6 compatible javac. You can try and let me know.References:
Annotation Processing Tool
JSR 269: Pluggable Annotation Processing API
Sun javac options
More blogs about glassfish and persistence