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
-persistenceUnit 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 BCEL, ASM
-checkonly : Just check the classes for enhancement status
-v : verbose output
where classpath must contain the following
datanucleus-enhancer.jar
datanucleus-core.jar
asm.jar (or bcel.jar if using ASM)
jdo2-api.jar
log4j.jar (optional)
your classes
your meta-data files
The 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/jdo2-api.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\jdo2-api.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 1.0.0) : Enhancement of classes
DataNucleus Enhancer : Classpath
>> /home/andy/work/myproject//target/classes
>> /home/andy/work/myproject/lib/log4j.jar
>> /home/andy/work/myproject/lib/jdo2-api.jar
>> /home/andy/work/myproject/lib/datanucleus-core.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 details
If 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).
Maven1 operates from a series of plugins. There is a DataNucleus plugin for Maven1 that allows enhancement of
classes. Go to the Download section of the website and download this. Once you have the Maven1 plugin,
you then need to set the properties for the plugin in your project.properties file. This will typically
not require any addition to your project.properties. If you do need to change this file, the following
parameters are the likely ones to change
maven.datanucleus.jdo.fileset.dir=${maven.build.dest} # Location of the JDO files
maven.datanucleus.jdo.fileset.include=**/*.jdo # fileset to include
#maven.datanucleus.jdo.fileset.exclude=something.jdo # fileset to exclude, if any
maven.datanucleus.classes.dir=${maven.build.dest} # Location of classes to enhance
maven.datanucleus.api=JDO # API to enhance to (JDO, JPA)
maven.datanucleus.enhancer.classenhancer=asm # Use ASM
maven.datanucleus.inputmode=files # Mode of input. Can also be set to "persistenceunit"
maven.datanucleus.persistenceunit= # Name of the persistence-unit to enhance
maven.datanucleus.log4j.configuration= # Log definition to use
maven.datanucleus.verbose=true # Turn on more output ?
You then run the Maven DataNucleus plugin, as follows
maven 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
maven datanucleus:enhance-check
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 Maven1 plugin,
you then need to set the properties for the plugin in your project.properties file. This will typically
not require any addition to your
pom.xml
. If you do need to change this file, the following
parameters are the likely ones to change
Configuration name Default Value Description
mappingIncludes **/*.jdo Fileset to include
mappingExcludes Fileset to exclude, if any
log4jConfiguration {internal props} Log definition to use
verbose false Turn on more output ?
You then run the Maven2 DataNucleus plugin, as follows
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>datanucleus</groupId>
<artifactId>datanucleus-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<log4jConfiguration>${basedir}/log4j.properties</log4jConfiguration>
<verbose>true</verbose>
</configuration>
<executions>
<execution>
<phase>compile</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
,
asm.jar
,
log4j.jar
and
jdo2-api.jar
are in your classpath. In the DataNucleus Enhancer Ant task, the following parameters are available
|
Parameter
|
Description
|
values
|
|
dir
|
Optional. Directory containing the JDO files to use for enhancing. Uses ant build file directory
if the parameter is not specified.
|
|
|
destination
|
Optional. Defining a directory where enhanced classes will be written. If omitted, the original
classes are updated.
|
|
|
api
|
Optional. Defines the API to be used when enhancing
|
JDO
, JPA
|
|
enhancerName
|
Optional. Defines the ClassEnhancer to use when enhancing.
|
ASM
| BCEL
|
|
persistenceUnit
|
Optional. Defines the "persistence-unit" to enhance.
|
|
|
checkonly
|
Whether to just check the classes for enhancement status. Will respond for each class with
"ENHANCED" or "NOT ENHANCED".
This will disable the enhancement process and just perform these
checks.
|
true,
false
|
|
verbose
|
Whether to have verbose output.
|
true,
false
|
|
filesuffixes
|
Optional. Suffixes to accept for the input files. The Enhancer Ant Task will scan for the files
having these suffixes under the directory specified by
dir
option. The value can include
comma-separated list of suffixes. If using annotations you can have "class" included as a valid
suffix here or use the
fileset
.
|
jdo
|
|
fileset
|
Optional. Defines the files to accept as the input files. Fileset enables finer control to which
classes / metadata files are accepted to enhanced. If one or more files are found in the fileset,
the Enhancer Ant Task will not scan for additional files defined by the option
filesuffixes
. For more information on defining a fileset, see
Apache FileSet Manual.
|
|
|
if
|
Optional. The name of a property that must be set in order to the Enhancer Ant Task to execute.
|
|
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: BCEL or ASM,
DataNucleus Core and DataNucleus Enhancer libraries.
To enable runtime enhancement, the
javaagent
option must be set in the java command line.
Example:
java -javaagent:datanucleus-enhancer-1.0-SNAPSHOT.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-1.0-SNAPSHOT.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.
Please take care over the following when using runtime enhancement
-
When you have a class with a field of another persistable type
make sure that you mark that field as "persistent" (@Persistent, or in XML)
since with runtime enhancement at that point the related class is likely
not yet enhanced so will likely not be marked as persistent otherwise.
Be explicit
You could alternatively programmatively enhance classes from within your application.
This is done as follows
import org.datanucleus.enhancer.DataNucleusEnhancer;
...
DataNucleusEnhancer enhancer = new DataNucleusEnhancer();
enhancer.setApi("JDO");
enhancer.setVerbose(true);
enhancer.setPersistenceUnitName("MyPersistenceUnit");
enhancer.execute();
This will look in META-INF/persistence.xml and enhance all classes defined by that unit.