As is described in the ByteCode Enhancement guide, DataNucleus utilises the common technique of byte-code manipulation to make your normal Java classes "persistable". The mechanism provided by DataNucleus is to use an "enhancer" process to perform this manipulation before you use your classes at runtime. The process is very quick and easy. How to use the DataNucleus Enhancer depends on what environment you are using. Below are some typical examples.
DataNucleus provides a JAR containing the Enhancer ( datanucleus-enhancer.jar ). If you are building your application manually and want to enhance your classes you follow the instructions in this section. You invoke the enhancer as follows
java -cp classpath org.datanucleus.enhancer.DataNucleusEnhancer [options] [jdo-files] [class-files]
where options can be
-pu {persistence-unit-name} : Name of a "persistence-unit" to enhance the classes for
-d {target-dir-name} : Write the enhanced classes to the specified directory
-api {api-name} : Name of the API we are enhancing for (JDO, JPA). Default is JDO
-enhancerName {name} : Name of the ClassEnhancer to use. Options ASM
-checkonly : Just check the classes for enhancement status
-v : verbose output
-q : quiet mode (no output, overrides verbose flag too)
-generatePK {flag} : generate any PK classes where needed
({flag} should be true or false - default=true)
-generateConstructor {flag} : generate default constructor where needed
({flag} should be true or false - default=true)
where classpath must contain the following
datanucleus-enhancer.jar
datanucleus-core.jar
datanucleus-api-jdo.jar/datanucleus-api-jpa.jar (if using JDO or JPA respectively)
asm.jar
jdo-api.jar
log4j.jar (optional)
jpa-api.jar (optional - if using JPA)
your classes
your meta-data filesThe input to the enhancer should be either a set of MetaData/class files or the name of the "persistence-unit" to enhance. In the first option, if any classes have annotations then they must be specified. All classes and MetaData files should be in the CLASSPATH when enhancing. To give an example of how you would invoke the enhancer
Linux/Unix :
java -cp target/classes:lib/datanucleus-enhancer.jar:lib/datanucleus-core.jar:lib/jdo-api.jar:
lib/datanucleus-api-jdo.jar:lib/log4j.jar:lib/asm.jar
-Dlog4j.configuration=file:log4j.properties
org.datanucleus.enhancer.DataNucleusEnhancer
**/*.jdo
Windows :
java -cp target\classes;lib\datanucleus-enhancer.jar;lib\datanucleus-core.jar;lib\jdo-api.jar;
lib\datanucleus-api-jdo.jar;lib\log4j.jar;lib\asm.jar
-Dlog4j.configuration=file:log4j.properties
org.datanucleus.enhancer.DataNucleusEnhancer -v
target/classes/org/mydomain/mypackage1/package.jdo
target/classes/org/mydomain/mypackage2/package.jdo
[should all be on same line. Shown like this for clarity]So you pass in your JDO MetaData files (and/or the class files wihich use annotations) as the final argument(s) in the list, and include the respective JAR's in the classpath (-cp). The enhancer responds as follows
DataNucleus Enhancer (version 3.0.0.m1) : Enhancement of classes
DataNucleus Enhancer : Classpath
>> /home/andy/work/myproject//target/classes
>> /home/andy/work/myproject/lib/log4j.jar
>> /home/andy/work/myproject/lib/jdo-api.jar
>> /home/andy/work/myproject/lib/datanucleus-core.jar
>> /home/andy/work/myproject/lib/datanucleus-api-jdo.jar
>> /home/andy/work/myproject/lib/datanucleus-enhancer.jar
>> /home/andy/work/myproject/lib/asm.jar
DataNucleus Enhancer : Using ClassEnhancer "asm" for API "JDO"
DataNucleus Enhancer : Input Files
>> /home/andy/work/myproject/target/classes/org/mydomain/mypackage1/package.jdo
>> /home/andy/work/myproject/target/classes/org/mydomain/mypackage2/package.jdo
Processing class "org.mydomain.mypackage1.Pack"
ENHANCED: org.mydomain.mypackage1.Pack
Processing class "org.mydomain.mypackage1.Card"
ENHANCED: org.mydomain.mypackage1.Card
Processing class "org.mydomain.mypackage2.Pack"
ENHANCED: org.mydomain.mypackage2.Pack
Processing class "org.mydomain.mypackage2.Card"
ENHANCED: org.mydomain.mypackage2.Card
DataNucleus Enhancer completed with success for 4 classes. Timings : input=422 ms, enhance=490 ms, total=912 ms.
... Consult the log for full detailsIf you have errors here relating to "Log4J" then you must fix these first. If you receive no output about which class was ENHANCED then you should look in the DataNucleus enhancer log for errors. The enhancer performs much error checking on the validity of the passed MetaData and the majority of errors are caught at this point. You can also use the DataNucleus Enhancer to check whether classes are enhanced. To invoke the enhancer in this mode you specify the checkonly flag. This will return a list of the classes, stating whether each class is enhanced for persistence under JDO or not. The classes need to be in the CLASSPATH (Please note that a CLASSPATH should contain a set of JAR's, and a set of directories. It should NOT explictly include class files, and should NOT include parts of the package names. If in doubt please consult a Java book).
Maven2 operates from a series of plugins. There is a DataNucleus plugin for Maven2 that allows enhancement of classes. Go to the Download section of the website and download this. Once you have the M2 plugin, you then need to set any properties for the plugin in your pom.xml file. If you are using annotations then you'll need to add *.class to "mappingIncludes" for example. Some properties that you may need to change are below
You then run the Maven2 DataNucleus plugin, as follows mvn datanucleus:enhance This will enhance all classes found that correspond to the classes defined in the JDO files in your source tree. If you want to check the current status of enhancement you can also type mvn datanucleus:enhance-check Or alternatively, you could add the following to your POM
<build>
...
<plugins>
<plugin>
<groupId>org.datanucleus</groupId>
<artifactId>maven-datanucleus-plugin</artifactId>
<version>2.0.0-release</version>
<configuration>
<log4jConfiguration>${basedir}/log4j.properties</log4jConfiguration>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>enhance</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
...
</build>So you then get auto-enhancement after each compile
Ant provides a powerful framework for performing tasks. DataNucleus provides an Ant task to enhance classes. DataNucleus provides a JAR containing the Enhancer ( datanucleus-enhancer.jar ). You need to make sure that the datanucleus-enhancer.jar , datanucleus-core.jar , datanucleus-api-jdo.jar / datanucleus-api-jpa.jar (if using JDO or JPA respectively), asm.jar , log4j.jar and jdo-api.jar are in your CLASSPATH. Additionally, if using JPA, you will need jpa-api.jar in the CLASSPATH too. In the DataNucleus Enhancer Ant task, the following parameters are available
The enhancer task extends the Apache Ant Java task, thus all parameters available to the Java task are also available to the enhancer task. So you could define something like the following, setting up the parameters enhancer.classpath , jdo.file.dir , and log4j.config.file to suit your situation (the jdo.file.dir is a directory containing the JDO files defining the classes to be enhanced). The classes specified by the XML Meta-Data files, together with the XML Meta-Data files must be in the CLASSPATH (Please note that a CLASSPATH should contain a set of JAR's, and a set of directories. It should NOT explictly include class files, and should NOT include parts of the package names. If in doubt please consult a Java book).
<target name="enhance" description="DataNucleus enhancement">
<taskdef name="datanucleusenhancer" classpathref="enhancer.classpath"
classname="org.datanucleus.enhancer.tools.EnhancerTask" />
<datanucleusenhancer classpathref="enhancer.classpath"
dir="${jdo.file.dir}" failonerror="true" verbose="true">
<jvmarg line="-Dlog4j.configuration=${log4j.config.file}"/>
</datanucleusenhancer>
</target>You can also define the files to be enhanced using a fileset . When a fileset is defined, the Enhancer Ant Task will not scan for additional files, and the option filesuffixes is ignored.
<target name="enhance" description="DataNucleus enhancement">
<taskdef name="datanucleusenhancer" classpathref="enhancer.classpath"
classname="org.datanucleus.enhancer.tools.EnhancerTask" />
<datanucleusenhancer
dir="${jdo.file.dir}" failonerror="true" verbose="true">
<fileset dir="${classes.dir}">
<include name="**/*.jdo"/>
<include name="**/acme/annotated/persistentclasses/*.class"/>
</fileset>
<classpath>
<path refid="enhancer.classpath"/>
</classpath>
</datanucleusenhancer>
</target>You can disable the enhancement execution upon the existence of a property with the usage of the if parameter.
<target name="enhance" description="DataNucleus enhancement">
<taskdef name="datanucleusenhancer" classpathref="enhancer.classpath"
classname="org.datanucleus.enhancer.tools.EnhancerTask" if="aPropertyName"/>
<datanucleusenhancer classpathref="enhancer.classpath"
dir="${jdo.file.dir}" failonerror="true" verbose="true">
<jvmarg line="-Dlog4j.configuration=${log4j.config.file}"/>
</datanucleusenhancer>
</target>
Enhancement of persistent classes at runtime is possible when using JRE 1.5 or superior versions. Runtime Enhancement requires the following runtime dependencies: ASM, and DataNucleus Core libraries. To enable runtime enhancement, the javaagent option must be set in the java command line. For example, java -javaagent:datanucleus-enhancer.jar Main The statement above will mean that all classes, when being loaded, will be processed by the ClassFileTransformer (except class in packages "java.*", "javax.*", "org.datanucleus.*"). This means that it can be slow since the MetaData search algorithm will be utilised for each. To speed this up you can specify an argument to that command specifying the names of package(s) that should be processed (and all others will be ignored). Like this
java -javaagent:datanucleus-enhancer.jar=mydomain.mypackage1,mydomain.mypackage2 Main
so in this case only classes being loaded that are in mydomain.mypackage1 and mydomain.mypackage2 will be attempted to be enhanced. For JPA, it would look like this
java -javaagent:datanucleus-enhancer.jar=-api=JPA,mydomain.mypackage1,mydomain.mypackage2 Main
Please take care over the following when using runtime enhancement
You could alternatively programmatively enhance classes from within your application. This is done as follows
import javax.jdo.JDOEnhancer;
JDOEnhancer enhancer = JDOHelper.getEnhancer();
enhancer.setVerbose(true);
enhancer.addPersistenceUnit("MyPersistenceUnit");
enhancer.enhance();This will look in META-INF/persistence.xml and enhance all classes defined by that unit.
DataNucleus provides a JAR containing the Enhancer ( datanucleus-enhancer.jar ). From JDK 1.6 and forward you can automatically enhance your classes when compiling your classes, as long as your classes have annotations (since this is an AnnotationProcessor ). To do this you need to
If using Eclipse you would need to use an Ant build.xml because the Eclipse compiler doesn't support specification of the processor compiler argument. However with Eclipse you can always just use the DataNucleus Eclipse plugin! To enhance classes for JPA (rather than JDO) using this method you need to specify -AenhanceAPI=JPA as a compiler argument. |