JPOX
JPOX
 Project  |  Ver 1.1  |  Ver 1.2  |  JDO  |  JPA  |  Guides  |  Tools
1.1 | Preparation | O/R Mapping | Runtime | Extensions | Developer
JPOX 1.1 Runtime
Runtime Tools
Queries
RDBMS Datastores
Class enhancement

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, 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 MetaData for these classes like this

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

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 allows the use of a byte-code enhancer that converts the users normal classes to implement this interface. JPOX provides its own byte-code enhancer (this can be found in the jpox-enhancer.jar). This section describes how to use this enhancer with JPOX. The JPOX enhancer fully implements JDO2 and so is the recommended choice when using JDO2. 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.

How to use the JPOX Enhancer depends on what environment you are using. Below are some typical examples.

Byte-Code Enhancement Myths

Some groups perpetuate arguments against "byte-code enhancement" saying that it is somehow 'evil'. The most common are :-

  • 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.

Manually

JPOX provides a JAR containing the Enhancer (jpox-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.jpox.enhancer.JPOXEnhancer [options] [jdo-files] [class-files]
    where options can be
        -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)
        -enhancerName name : Name of the ClassEnhancer to use (BCEL)
        -checkonly : Just check the classes for enhancement status
        -verify : Verify the classes
        -v : verbose output

    where classpath MUST contain the following
        jpox-enhancer.jar
        jpox.jar
        bcel.jar
        jdo2-api.jar
        log4j.jar
        your classes
        your meta-data files

If your classes have metadata files then you must provide them. If your classes use annotations then you just provide the class files. To give an example of how you would invoke the enhancer

Linux/Unix :
java -cp target/classes:lib/jpox-enhancer.jar:lib/jpox.jar:lib/jdo2-api.jar:lib/log4j.jar:lib/bcel.jar
     -Dlog4j.configuration=file:log4j.properties
     org.jpox.enhancer.JPOXEnhancer 
     **/*.jdo

Windows :
java -cp target\classes;lib\jpox-enhancer.jar;lib\jpox.jar;lib\jdo2-api.jar;lib\log4j.jar;lib\bcel.jar
     -Dlog4j.configuration=file:log4j.properties
     org.jpox.enhancer.JPOXEnhancer -v
     target/classes/org/jpox/examples/inverse/package.jdo
     target/classes/org/jpox/examples/normal/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

JPOX Enhancer (version 1.1.0) : Enhancement of classes

JPOX Enhancer : Classpath
>>  /home/andy/work/JPOX/samples/packofcards/target/classes
>>  /home/andy/work/JPOX/samples/packofcards/lib/log4j.jar
>>  /home/andy/work/JPOX/samples/packofcards/lib/jdo2-api.jar
>>  /home/andy/work/JPOX/samples/packofcards/lib/jpox.jar
>>  /home/andy/work/JPOX/samples/packofcards/lib/jpox-enhancer.jar
>>  /home/andy/work/JPOX/samples/packofcards/lib/bcel.jar

JPOX Enhancer : Input Files
>>  /home/andy/work/JPOX/samples/packofcards/target/classes/org/jpox/examples/inverse/package.jdo
>>  /home/andy/work/JPOX/samples/packofcards/target/classes/org/jpox/examples/normal/package.jdo

Processing class "org.jpox.examples.inverse.Pack"
ENHANCED: org.jpox.examples.inverse.Pack
Processing class "org.jpox.examples.inverse.Card"
ENHANCED: org.jpox.examples.inverse.Card
Processing class "org.jpox.examples.normal.Pack"
ENHANCED: org.jpox.examples.normal.Pack
Processing class "org.jpox.examples.normal.Card"
ENHANCED: org.jpox.examples.normal.Card

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 JPOX 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 JPOX 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

Maven1 operates from a series of plugins. There is a JPOX 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.jpox.jdo.fileset.dir=${maven.build.dest}  # Location of the JDO files
maven.jpox.jdo.fileset.include=**/*.jdo         # fileset to include
#maven.jpox.jdo.fileset.exclude=something.jdo   # fileset to exclude, if any
maven.jpox.classes.dir=${maven.build.dest}      # Location of classes to enhance
maven.jpox.log4j.configuration=                 # Log definition to use
maven.jpox.verbose=true                         # Turn on more output ?

You then run the Maven JPOX plugin, as follows

maven jpox: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 jpox:enhance-check


Maven2

Maven2 operates from a series of plugins. There is a JPOX 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 JPOX plugin, as follows

mvn jpox: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 jpox:enhance-check

Or alternatively, you could add the following to your POM

    <build>
        ...
        <plugins>
            <plugin>
                <groupId>jpox</groupId>
                <artifactId>jpox-maven-plugin</artifactId>
                <version>1.1.7</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

Ant provides a powerful framework for performing tasks. JPOX provides an Ant task to enhance classes. JPOX provides a JAR containing the Enhancer (jpox-enhancer.jar). You need to make sure that the jpox-enhancer.jar, jpox.jar, bcel.jar, log4j.jar and jdo2-api.jar are in your classpath. In the JPOX Enhancer Ant task, the following parameters are available

ParameterDescriptionvalues
dirOptional. Directory containing the JDO files to use for enhancing. Uses ant build file directory if the parameter is not specified.
destinationOptional. Defining a directory where enhanced classes will be written. If omitted, the original classes are updated.
apiOptional. Defines the API to be used when enhancingJDO, JPA
enhancerNameOptional. Defines the ClassEnhancer to use when enhancingBCEL
checkonlyWhether 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
verifyVerify the classes enhancement state. Performs more detailed checking on the enhancement consistency. This will disable the enhancement process and just perform these checks.true, false
verboseWhether to have verbose output.true, false
jdofilesuffixesSuffixes to accept for the input files. The value can include comma-separated list of options. If using annotations you need to have "class" included as a valid suffix herejdo

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 JDO Meta-Data files, together with the JDO 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="JPOX enhancement">
    <taskdef name="jpoxenhancer" classpathref="enhancer.classpath" classname="org.jpox.enhancer.tools.EnhancerTask" />

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