DataNucleus Enhancer

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] [mapping-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
        -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 "mapping-files" and "class-files" are provided when not enhancing a persistence-unit, 
        and give the paths to the mapping files and class-files that define the classes being enhanced.

    where classpath must contain the following
        datanucleus-api-jdo.jar/datanucleus-api-jpa.jar (if using JDO or JPA respectively)
        log4j.jar (optional)
        jpa-api.jar (optional - if using JPA)
        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/jdo-api.jar:

Windows :
java -cp target\classes;lib\datanucleus-enhancer.jar;lib\datanucleus-core.jar;lib\jdo-api.jar;
     org.datanucleus.enhancer.DataNucleusEnhancer -v

[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.1) : 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 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).


Maven operates from a series of plugins. There is a DataNucleus plugin for Maven that allows enhancement of classes. Go to the Download section of the website and download this. Once you have the Maven plugin, you then need to set any properties for the plugin in your pom.xml file. Some properties that you may need to change are below

Property Default Description
metadataDirectory ${} Directory to use for enhancement files (classes/mappings)
metadataIncludes **/*.jdo, **/*.class Fileset to include for enhancement (if not using persistence-unit)
metadataExcludes Fileset to exclude for enhancement (if not using persistence-unit)
persistenceUnitName Name of the persistence-unit to enhance (if not using metadataIncludes etc)
log4jConfiguration Config file location for Log4J (if using it)
jdkLogConfiguration Config file location for JDK1.4 logging (if using it)
api JDO API to enhance to (JDO, JPA)
verbose false Verbose output?
quiet false No output?
targetDirectory Where the enhanced classes are written (default is to overwrite them)
fork true Whether to fork the enhancer process
generatePK true Generate a PK class (of name {MyClass}_PK) for cases where there are multiple PK fields yet no PK class is defined.
generateConstructor true Generate a default constructor if not defined for the class being enhanced.
detachListener false Whether to enhance classes to make use of a detach listener for attempts to access an undetached field.

You will also may need to add datanucleus-api-jdo / datanucleus-api-jpa into the CLASSPATH (of the plugin, or your project) for the enhancer to operate, depending on which API you're using.

You then run the Maven 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


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

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
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
quiet Whether to have no output. true, false
generatePK Whether to generate PK classes as required. true , false
generateConstructor Whether to generate a default constructor as required. 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.

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="" />

    <datanucleusenhancer classpathref="enhancer.classpath"
        dir="${jdo.file.dir}" failonerror="true" verbose="true">
        <jvmarg line="-Dlog4j.configuration=${log4j.config.file}"/>

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="" />

        dir="${jdo.file.dir}" failonerror="true" verbose="true">
        <fileset dir="${classes.dir}">
            <include name="**/*.jdo"/>
            <include name="**/acme/annotated/persistentclasses/*.class"/>
            <path refid="enhancer.classpath"/>

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="" if="aPropertyName"/>

    <datanucleusenhancer classpathref="enhancer.classpath"
        dir="${jdo.file.dir}" failonerror="true" verbose="true">
        <jvmarg line="-Dlog4j.configuration=${log4j.config.file}"/>
Runtime Enhancement

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 :

  • 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
  • If the agent jar is not found make sure it is specified with an absolute path.
  • If using Spring, please be aware that some versions of Spring have a dependency on ASM v3.x and this may be pulled into the CLASSPATH in front of the ASM v4.x that DataNucleus requires. Please update your build mechanism to avoid this. Note that DataNucleus 3.2 repackages ASM internally so this problem will never happen there, so maybe upgrade to that version.

Parameter Description values
api Optional. Name of the API we are enhancing for. JDO | JPA

Programmatic API

You could alternatively programmatively enhance classes from within your application. This is done as follows

import javax.jdo.JDOEnhancer;

JDOEnhancer enhancer = JDOHelper.getEnhancer();

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

  1. Use JDK1.6+
  2. Add datanucleus-enhancer.jar , datanucleus-core.jar , datanucleus-api-jdo.jar / datanucleus-api-jpa.jar (depends if using JDO or JPA) jdo-api.jar and asm.jar to the compiler classpath
  3. Set the processor compiler argument to org.datanucleus.enhancer.EnhancerProcessor . In Maven you would add the following to your POM
  4. Classes will be enhanced when you compile
Note that this works by waiting a period of time until all classes will have been compiled before invoking the enhancement step. We advise against using it, and better to use post-compile directly

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.

Class enhancement

DataNucleus requires that all classes that are persisted implement PersistenceCapable , an interface defined by JDO. Why should we do this, Hibernate/TopLink dont need it ? . Well thats a simple question really

  • DataNucleus uses this PersistenceCapable interface, and adds it using bytecode enhancement techniques so that you never need to actually change your classes. This means that you get transparent persistence , and your classes always remain your classes. ORM tools that use a mix of reflection and/or proxies are not totally transparent.
  • DataNucleus' use of PersistenceCapable provides transparent change tracking. When any change is made to an object the change creates a notification to DataNucleus allowing it to be optimally persisted. ORM tools that dont have access to such change tracking have to use reflection to detect changes. The performance of this process will break down as soon as you read a large number of objects, but modify just a handful, with these tools having to compare all object states for modification at transaction commit time.

Why not also read this comparison of bytecode enhancement, and proxies. It gives a clear enough comparison of the relative benefits.

Note that even when using JPA, DataNucleus also requires bytecode enhancement. We make use of the very same JDO bytecode enhancement contract since it is a defined standard, so easier to adopt that for JPA than adding our own custom enhancement that does the same as JDO.

In a JDO-enabled application there are 3 categories of classes. These are PersistenceCapable , PersistenceAware and normal classes. The Meta-Data defines which classes fit into these categories. To give an example for JDO, we have 3 classes. The class A is to be persisted in the datastore. The class B directly updates the fields of class A but doesn't need persisting. The class C is not involved in the persistence process. We would define JDO MetaData for these classes like this

<class name="A" persistence-modifier="persistence-capable">
    <field name="myField">
<class name="B" persistence-modifier="persistence-aware">

So our MetaData is mainly for those classes that are PersistenceCapable and are to be persisted to the datastore (we don't really need the persistence-modifier for thse classes since this is the default). For PersistenceAware classes we simply notate that the class knows about persistence. We don't define MetaData for any class that has no knowledge of persistence.

JDO requires that all classes to be persisted must implement the PersistenceCapable interface . Users could manually do this themselves but this would impose work on them. JDO permits the use of a byte-code enhancer that converts the users normal classes to implement this interface. DataNucleus provides its own byte-code enhancer (this can be found in the datanucleus-enhancer.jar ). This section describes how to use this enhancer with DataNucleus. The DataNucleus enhancer fully implements JDO2 and so is the recommended choice when persisting using the JDO2 API. The enhancement process adds the necessary methods to the users class in order to implement PersistenceCapable .

The example above doesn't show all PersistenceCapable methods, but demonstrates that all added methods and fields are prefixed with "jdo" to distinguish them from the users own methods and fields. Also each persistent field of the class will be given a jdoGetXXX, jdoSetXXX method so that accesses of these fields are intercepted so that JDO can manage their "dirty" state.

The MetaData defines which classes are required to be persisted, and also defines which aspects of persistence each class requires. For example if a class has the detachable attribute set to true , then that class will be enhanced to also implement Detachable

Again, the example above doesn't show all methods added for the Detachable interface but the main thing to know is that the detached state (object id of the datastore object, the version of the datastore object when it was detached, and which fields were detached is stored in "jdoDetachedState"). Please see the JDO spec for more details.

If the MetaData is changed in any way during development, the classes should always be recompiled and re-enhanced afterwards.

Byte-Code Enhancement Myths

Some groups (e.g Hibernate) perpetuated arguments against "byte-code enhancement" saying that it was somehow 'evil'. The most common were :-

  • Slows down the code-test cycle . This is erroneous since you only need to enhance just before test and the provided plugins for Ant, Eclipse and Maven all do the enhancement job automatically and rapidly.
  • Is less "lazy" than the proxy approach since you have to load the object as soon as you get a pointer to it . In a 1-1 relation you have to load the object then since you would cause issues with null pointers otherwise. With 1-N relations you load the elements of the collection/map only when you access them and not the collection/map. Hardly an issue then is it!
  • Fail to detect changes to public fields unless you enhance your client code . Firstly very few people will be writing code with public fields since it is bad practice in an OO design, and secondly, this is why we have "PersistenceAware" classes.

So as you can see, there are no valid reasons against byte-code enhancement, and the pluses are that runtime detection of dirty events on objects is much quicker, hence your persistence layer operates faster without any need for iterative reflection-based checks. The fact is that Hibernate itself also now has a mode whereby you can do bytecode enhancement although not the default mode of Hibernate. So maybe it wasn't so evil after all ?


Many people will wonder what actually happens to a class upon bytecode enhancement. In simple terms the necessary methods and fields are added so as to implement PersistenceCapable . If you want to check this, just use a Java decompiler such as JD. It has a nice GUI allowing you to just select your class to decompile and shows you the source.