openjpa-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Patrick Linskey" <>
Subject unenhanced class support
Date Fri, 20 Jul 2007 18:42:03 GMT

Over the last week, I've been working on making OpenJPA work with
unenhanced classes in a variety of different environments. My goal has
been to make the enhancement step (either at build time or via the
javaagent) optional in order to remove a barrier to entry for
newcomers to OpenJPA. There are still reasons why enhancement is a
good thing to do in a running OpenJPA system, but my hope is that we
can make these be mostly quality-of-service issues, and not
functionality issues.

I've been pretty successful so far, but there are a few limitations in
some environments. I'd like to get some feedback about what to do
about these limitations. First, I'll describe my approach:

I started looking into this when Marc told me about the new
retransformation capabilities in Java 6. (Briefly, in Sun's Java 6
impl, it is no longer necessary to specify a javaagent flag in order
to retransform classes.) This led me to investigate retransforming
entity types to add field-tracking code to method blocks without
violating any of the retransformation rules. I combined this with a
subclassing approach so that instances created by OpenJPA (vs. created
by the user with 'new') can be treated as proper persistence-capable

Since retransformation does not allow fields, methods, or interfaces
to be added to a class, I added a helper class that maintains a static
map of *all* the instances created with 'new' that have been
persisted; this map associates a managed instance with a
ReflectingPersistenceCapable instance, which implements
PersistenceCapable via reflection, as the name implies, and can wrap
unenhanced managed instances for OpenJPA's needs.

So, the only functionality cost in a Java 6 environment is the extra
overhead of occasionally looking up the PersistenceCapable for a given
unenhanced managed instance. There is still a bit of a performance
cost, since I needed to do reflection in some places instead of direct
field access because of details of the class hierarchy and field
access restrictions.

In a Java 5 environment, if you specify a new javaagent class, then
the situation is exactly the same. IMO this improves on our current
javaagent in that it releases the restriction that persistent types
must be listed in the first persistence unit in persistence.xml, and
because the redefinition logic is never invoked against any
non-managed types.

If you do not specify a javaagent class in Java 5, then OpenJPA cannot
do redefinition. However, it can still create subclasses with logic in
overridden setters and getters. So, in Java 5 without a javaagent but
with property access, we only lose dirty tracking and lazy loading for
instances created by  the user code. This only matters for cases where
an instance so created is flushed (for dirty tracking) or cleared (for
lazy loading).

In Java 5 without a javaagent and with field access, things are a bit
worse -- OpenJPA can't do any dirty tracking or lazy loading, either
for instances created by the user code or for instances created by

We could improve the situation a bit for field access and post-flush
property access in Java 5 with no javaagent. This would require state
comparison, though, which is not the fastest thing in the world, and
requires that we hold hard references to all applicable instances for
the duration of the EM's life (all user-created property access
instances, and all field access instances regardless of how they were

So, I'm looking for answers to the following questions in particular:

1. what should we do about { Java 5, no javaagent, field access }?
Should we support this configuration, including the corresponding
extra overhead, or should we require either property access or a
javaagent specified in these configurations?

2. what should we do about { Java 5, no javaagent, property access,
flushed | cleared instances }? There is a much lower impact to doing
the dirty tracking in these configurations, since the scope is
narrower. However, we might also be able to just not allow flush or
clear or multiple sequential transactions if the persistence context
has references to unenhanced, unredefined user-created instances.


(Oh, and the code is still a work in progress -- everything I
discussed above is working, but serialization and cloning and
detachment are untested, and will probably require some tweaks to get
working correctly.)


Patrick Linskey
202 669 5907

View raw message