blob: ca4e792d77aa16bda1c05433d59aa1dd7b794606 [file] [log] [blame]
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>2.&nbsp; Enhancement</title><link rel="stylesheet" href="css/docbook.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.72.0"><link rel="start" href="manual.html" title="Apache OpenJPA User's Guide"><link rel="up" href="ref_guide_pc.html" title="Chapter&nbsp;5.&nbsp; Persistent Classes"><link rel="prev" href="ref_guide_pc.html" title="Chapter&nbsp;5.&nbsp; Persistent Classes"><link rel="next" href="ref_guide_pc_oid.html" title="3.&nbsp; Object Identity"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">2.&nbsp;
Enhancement
</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ref_guide_pc.html">Prev</a>&nbsp;</td><th width="60%" align="center">Chapter&nbsp;5.&nbsp;
Persistent Classes
</th><td width="20%" align="right">&nbsp;<a accesskey="n" href="ref_guide_pc_oid.html">Next</a></td></tr></table><hr></div><div class="section" lang="en"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="ref_guide_pc_enhance"></a>2.&nbsp;
Enhancement
</h2></div></div></div><div class="toc"><dl><dt><span class="section"><a href="ref_guide_pc_enhance.html#ref_guide_pc_enhance_build">2.1.
Enhancing at Build Time
</a></span></dt><dt><span class="section"><a href="ref_guide_pc_enhance.html#ref_guide_pc_enhance_runtime_container">2.2.
Enhancing JPA Entities on Deployment
</a></span></dt><dt><span class="section"><a href="ref_guide_pc_enhance.html#ref_guide_pc_enhance_runtime">2.3.
Enhancing at Runtime
</a></span></dt><dt><span class="section"><a href="ref_guide_pc_enhance.html#ref_guide_pc_enhance_unenhanced_types">2.4.
Omitting the OpenJPA enhancer
</a></span></dt></dl></div><a class="indexterm" name="d0e21025"></a><a class="indexterm" name="d0e21028"></a><p>
In order to provide optimal runtime performance, flexible lazy loading, and
efficient, immediate dirty tracking, OpenJPA can use an <span class="emphasis"><em>enhancer
</em></span>. An enhancer is a tool that automatically adds code to your
persistent classes after you have written them. The enhancer post-processes the
bytecode generated by your Java compiler, adding the necessary fields and
methods to implement the required persistence features. This bytecode
modification perfectly preserves the line numbers in stack traces and is
compatible with Java debuggers. In fact, the only change to debugging
is that the persistent setter and getter methods of entity classes using
property access will be prefixed with <code class="literal">pc</code> in stack traces and
step-throughs. For example, if your entity has a <code class="methodname">getId</code>
method for persistent property <code class="literal">id</code>, and that method throws an
exception, the stack trace will report the exception from method <code class="methodname">
pcgetId</code>. The line numbers, however, will correctly correspond to
the <code class="methodname">getId</code> method in your source file.
</p><div class="mediaobject"><table border="0" summary="manufactured viewport for HTML img" cellspacing="0" cellpadding="0" width="339"><tr><td><img src="img/enhancement.png"></td></tr></table></div><p>
The diagram above illustrates the compilation of a persistent class.
</p><p>
You can add the OpenJPA enhancer to your build process, or use Java 1.5's
instrumentation features to transparently enhance persistent classes when they
are loaded into the JVM. The following sections describe each option.
</p><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_pc_enhance_build"></a>2.1.&nbsp;
Enhancing at Build Time
</h3></div></div></div><a class="indexterm" name="d0e21064"></a><p>
The enhancer can be invoked at build time
via its Java class, <code class="classname">
org.apache.openjpa.enhance.PCEnhancer</code>.
</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3><p>
You can also enhance via Ant; see
<a href="ref_guide_integration.html#ref_guide_integration_enhance" title="1.2.&nbsp; Enhancer Ant Task">Section&nbsp;1.2, &#8220;
Enhancer Ant Task
&#8221;</a>.
</p></div><div class="example"><a name="ref_guide_pc_enhance_enhancer"></a><p class="title"><b>Example&nbsp;5.1.&nbsp;
Using the OpenJPA Enhancer
</b></p><div class="example-contents"><pre class="programlisting">
java org.apache.openjpa.enhance.PCEnhancer Magazine.java
</pre></div></div><br class="example-break"><p>
The enhancer accepts the standard set of command-line arguments defined by the
configuration framework (see <a href="ref_guide_conf_devtools.html" title="3.&nbsp; Command Line Configuration">Section&nbsp;3, &#8220;
Command Line Configuration
&#8221;</a> ),
along with the following flags:
</p><div class="itemizedlist"><ul type="disc"><li><p>
<code class="literal">-directory/-d &lt;output directory&gt;</code>: Path to the output
directory. If the directory does not match the enhanced class' package, the
package structure will be created beneath the directory. By default, the
enhancer overwrites the original <code class="filename">.class</code> file.
</p></li><li><p>
<code class="literal">-enforcePropertyRestrictions/-epr &lt;true/t | false/f&gt;</code>:
Whether to throw an exception when it appears that a property access entity is
not obeying the restrictions placed on property access. Defaults to false.
</p></li><li><p>
<code class="literal">-addDefaultConstructor/-adc &lt;true/t | false/f&gt;</code>: The
spec requires that all persistent classes define a no-arg constructor. This flag
tells the enhancer whether to add a protected no-arg constructor to any
persistent classes that don't already have one. Defaults to <code class="literal">
true</code>.
</p></li><li><p>
<code class="literal">-tmpClassLoader/-tcl &lt;true/t | false/f&gt;</code>: Whether to
load persistent classes with a temporary class loader. This allows other code to
then load the enhanced version of the class within the same JVM. Defaults to
<code class="literal">true</code>. Try setting this flag to <code class="literal">false</code> as a
debugging step if you run into class loading problems when running the enhancer.
</p></li></ul></div><p>
Each additional argument to the enhancer must be one of the following:
</p><div class="itemizedlist"><ul type="disc"><li><p>
The full name of a class.
</p></li><li><p>
The .java file for a class.
</p></li><li><p>
The <code class="filename">.class</code> file of a class.
</p></li></ul></div><p>
If you do not supply any arguments to the enhancer, it will run on the classes
in your persistent class list (see <a href="ref_guide_pc.html#ref_guide_pc_pcclasses" title="1.&nbsp; Persistent Class List">Section&nbsp;1, &#8220;
Persistent Class List
&#8221;</a>).
</p><p>
You can run the enhancer over classes that have already been enhanced, in which
case it will not further modify the class. You can also run it over classes that
are not persistence-capable, in which case it will treat the class as
persistence-aware. Persistence-aware classes can directly manipulate the
persistent fields of persistence-capable classes.
</p><p>
Note that the enhancement process for subclasses introduces dependencies on the
persistent parent class being enhanced. This is normally not problematic;
however, when running the enhancer multiple times over a subclass whose parent
class is not yet enhanced, class loading errors can occur. In the event of a
class load error, simply re-compile and re-enhance the offending classes.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_pc_enhance_runtime_container"></a>2.2.&nbsp;
Enhancing JPA Entities on Deployment
</h3></div></div></div><a class="indexterm" name="d0e21151"></a><p>
The Java EE 5 specification includes hooks to automatically enhance JPA entities
when they are deployed into a container. Thus, if you are using a Java EE
5-compliant application server, OpenJPA will enhance your entities automatically
at runtime. Note that if you prefer build-time enhancement, OpenJPA's runtime
enhancer will correctly recognize and skip pre-enhanced classes.
</p><p>
If your application server does not support the Java EE 5 enhancement hooks,
consider using the build-time enhancement described above, or the more general
runtime enhancement described in the next section.
</p></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_pc_enhance_runtime"></a>2.3.&nbsp;
Enhancing at Runtime
</h3></div></div></div><a class="indexterm" name="d0e21165"></a><p>
OpenJPA includes a <span class="emphasis"><em>Java agent</em></span> for automatically enhancing
persistent classes as they are loaded into the JVM. Java agents are classes that
are invoked prior to your application's <code class="methodname">main</code> method.
OpenJPA's agent uses JVM hooks to intercept all class loading to enhance classes
that have persistence metadata before the JVM loads them.
</p><p>
Searching for metadata for every class loaded by the JVM can slow application
initialization. One way to speed things up is to take advantage of the optional
persistent class list described in <a href="ref_guide_pc.html#ref_guide_pc_pcclasses" title="1.&nbsp; Persistent Class List">Section&nbsp;1, &#8220;
Persistent Class List
&#8221;</a>. If
you declare a persistent class list, OpenJPA will only search for
metadata for classes in that list.
</p><p>
To employ the OpenJPA agent, invoke <code class="literal">java</code> with the <code class="literal">
-javaagent</code> set to the path to your OpenJPA jar file.
</p><div class="example"><a name="ref_guide_pc_enhance_runtime_ex"></a><p class="title"><b>Example&nbsp;5.2.&nbsp;
Using the OpenJPA Agent for Runtime Enhancement
</b></p><div class="example-contents"><pre class="programlisting">
java -javaagent:/home/dev/openjpa/lib/openjpa.jar com.xyz.Main
</pre></div></div><br class="example-break"><p>
You can pass settings to the agent using OpenJPA's plugin syntax (see
<a href="ref_guide_conf_plugins.html" title="4.&nbsp; Plugin Configuration">Section&nbsp;4, &#8220;
Plugin Configuration
&#8221;</a>). The agent accepts the long
form of any of the standard configuration options
(<a href="ref_guide_conf_devtools.html" title="3.&nbsp; Command Line Configuration">Section&nbsp;3, &#8220;
Command Line Configuration
&#8221;</a> ). It also accepts the following
options, the first three of which correspond exactly to to the same-named
options of the enhancer tool described in
<a href="ref_guide_pc_enhance.html#ref_guide_pc_enhance_build" title="2.1.&nbsp; Enhancing at Build Time">Section&nbsp;2.1, &#8220;
Enhancing at Build Time
&#8221;</a>:
</p><div class="itemizedlist"><ul type="disc"><li><p>
<code class="literal">addDefaultConstructor</code>
</p></li><li><p>
<code class="literal">enforcePropertyRestrictions</code>
</p></li><li><p>
<code class="literal">scanDevPath</code>: Boolean indicating whether to scan the
classpath for persistent types if none have been configured. If you do not
specify a persistent types list and do not set this option to true, OpenJPA will
check whether each class loaded into the JVM is persistent, and enhance it
accordingly. This may slow down class load times significantly.
</p></li><li><p>
<code class="literal">classLoadEnhancement</code>: Boolean controlling whether OpenJPA
load-time class enhancement should be available in this JVM execution. Default:
<code class="literal">true</code>
</p></li><li><p>
<code class="literal">runtimeRedefinition</code>: Boolean controlling whether OpenJPA
class redefinition should be available in this JVM execution. Default:
<code class="literal">true</code>
</p></li></ul></div><div class="example"><a name="ref_guide_pc_enhance_runtime_opt_ex"></a><p class="title"><b>Example&nbsp;5.3.&nbsp;
Passing Options to the OpenJPA Agent
</b></p><div class="example-contents"><pre class="programlisting">
java -javaagent:/home/dev/openjpa/lib/openjpa.jar=addDefaultConstructor=false com.xyz.Main
</pre></div></div><br class="example-break"></div><div class="section" lang="en"><div class="titlepage"><div><div><h3 class="title"><a name="ref_guide_pc_enhance_unenhanced_types"></a>2.4.&nbsp;
Omitting the OpenJPA enhancer
</h3></div></div></div><a class="indexterm" name="d0e21250"></a><p>
OpenJPA does not require that the enhancer be run. If you do not run the
enhancer, OpenJPA will fall back to one of several possible alternatives for
state tracking, depending on the execution environment.
</p><div class="itemizedlist"><ul type="disc"><li><p>
<span class="emphasis"><em>Deploy-time enhancement</em></span>: if you are running your
application inside a Java EE 5 container, or another environment that supports
the JPA container contract, then OpenJPA will automatically perform class
transformation at deploy time.
</p></li><li><p>
<span class="emphasis"><em>Java 6 class retransformation</em></span>: if you are running your
application in a Java 6 environment, OpenJPA will attempt to dynamically
register a <code class="literal">ClassTransformer</code> that will redefine your
persistent classes on the fly to track access to persistent data. Additionally,
OpenJPA will create a subclass for each of your persistent classes. When
you execute a query or traverse a relation, OpenJPA will return an instance
of the subclass. This means that the <code class="literal">instanceof</code> operator
will work as expected, but <code class="literal">o.getClass()</code> will return the
subclass instead of the class that you wrote.
</p><p>
You do not need to do anything at all to get this behavior. OpenJPA will
automatically detect whether or not the execution environment is capable of
Java 6 class retransformation.
</p></li><li><p>
<span class="emphasis"><em>Java 5 class redefinition</em></span>: if you are running your
application in a Java 5 environment, and you specify the OpenJPA javaagent,
OpenJPA will use Java 5 class redefinition to redefine any persistent classes
that are not enhanced by thet OpenJPA javaagent. Aside from the requirement
that you specify a javaagent on the command line, this behavior is exactly the
same as the Java 6 class retransformation behavior. Of course, since the
OpenJPA javaagent performs enhancement by default, this will only be available
if you set the <code class="literal">classLoadEnhancement</code> javaagent flag to
<code class="literal">false</code>, or on any classes that are skipped by the OpenJPA
runtime enhancement process for some reason.
</p></li><li><p>
<span class="emphasis"><em>Runtime Unenhanced Classes</em></span>: AKA statte comparison and
subclassing. If you are running
in a Java 5 environment without a javaagent, or in a Java 6 environment that
does not support class retransformation, OpenJPA will still create subclasses
as outlined above. However, in some cases, OpenJPA may not be able to receive
notifications when you read or write persistent data.
</p><p>
</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><h3 class="title">Note</h3>
Runtime Unenhanced Classes has some known limitations which are discussed below
and documented in JIRA issues on the OpenJPA website. Support for this method
of automatic enhancement may be enabled or disabled via the
<a href="ref_guide_conf_openjpa.html#openjpa.RuntimeUnenhancedClasses" title="5.56.&nbsp;openjpa.RuntimeUnenhancedClasses">Section&nbsp;5.56, &#8220;openjpa.RuntimeUnenhancedClasses&#8221;</a>option.
</div><p>
</p><p>
If you are using <span class="emphasis"><em>property access</em></span> for your persistent data,
then OpenJPA will be able to track all accesses for instances that you load
from the database, but not for instances that you create. This is because
OpenJPA will create new instances of its dynamically-generated subclass when
it loads data from the database. The dynamically-generated subclass has
code in the setters and getters that notify OpenJPA about persistent data
access. This means that new instances that you create will be subject to
state-comparison checks (see discussion below) to compute which fields to
write to the database, and that OpenJPA will ignore requests to evict
persistent data from such instances. In practice, this is not a particularly
bad limitation, since OpenJPA already knows that it must insert all field
values for new instances. So, this is only really an issue if you flush
changes to the database while inserting new records; after such a flush,
OpenJPA will need to hold potentially-unneeded hard references to the
new-flushed instances.
</p><p>
If you are using <span class="emphasis"><em>field access</em></span> for your persistent data,
then OpenJPA will not be able to track accesses for any instances, including
ones that you load from the database. So, OpenJPA will perform state-comparison
checks to determine which fields are dirty. These state comparison checks are
costly in two ways. First, there is a performance penalty at flush / commit
time, since OpenJPA must walk through every field of every instance to determine
which fields of which records are dirty. Second, there is a memory penalty,
since OpenJPA must hold hard references to all instances that were loaded at
any time in a given transaction, and since OpenJPA must keep a copy of all
the initial values of the loaded data for later comparison. Additionally,
OpenJPA will ignore requests to evict persistent state for these types of
instances. Finally, the default lazy loading configuration will be ignored for
single-valued fields (one-to-one, many-to-one, and any other non-collection
or non-map field that has a lazy loading configuration). If you use fetch
groups or programmatically configure your fetch plan, OpenJPA will obey these
directives, but will be unable to lazily load any data that you exclude from
loading. As a result of these limitations, it is not recommended that you use
field access if you are not either running the enhancer or using OpenJPA with
a javaagent or in a Java 6 environment.
</p></li></ul></div></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ref_guide_pc.html">Prev</a>&nbsp;</td><td width="20%" align="center"><a accesskey="u" href="ref_guide_pc.html">Up</a></td><td width="40%" align="right">&nbsp;<a accesskey="n" href="ref_guide_pc_oid.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">Chapter&nbsp;5.&nbsp;
Persistent Classes
&nbsp;</td><td width="20%" align="center"><a accesskey="h" href="manual.html">Home</a></td><td width="40%" align="right" valign="top">&nbsp;3.&nbsp;
Object Identity
</td></tr></table></div></body></html>