Hey Andrus,
You were of course right ;-)
I was sure there was an easy way to make it work because I could run
the test with Hibernate and it worked fine. But as I looked into the
internals of Hibernate its not actually instrumenting any classes for
this test case. I played around a bit and could not get it to
instrument anything so I decided to move on.
I'll continue to assume a managed env until I can get something
going. And then I'll come back to the non-managed env.
TTFN,
Bill Dudney
MyFaces - http://myfaces.apache.org
Cayenne - http://incubator.apache.org/projects/cayenne.html
On Mar 28, 2006, at 12:05 AM, Andrus Adamchik wrote:
I suggested to postpone the discussion, but here is one more
note :-) Let me clarify - I understand how JPA runtime can get
access to enhanced classes. The problem is that the same class can
also be accessed directly in the application, bypassing JPA runtime
(just like in my unit test) - that's what causes the problem.
Andrus
On Mar 28, 2006, at 10:55 AM, Andrus Adamchik wrote:
app class loader will not be getting at the classes directly but
instead will be using the persistence unit's class loader.
That's what I thought initially too. Only after trying to make it
work with test cases I realized the problem. With hierarchical
ClassLoaders, a ClassLoader can either load classes directly or
get them from its parent, but not from a child or a peer loader.
In Java EE you can tweak loader hierarchy at the container level
(or register ClassTransformers with the custom app ClassLoader
subclass), so this is not a problem. AFAIK in Java SE you can't,
except by using instrumentation API.
I hope I've overlooked something basic. So how about this. Since
you and Jeff will be working on the enhancer shortly, let's
postpone this discussion till we can test the enhancer. It would
be great if someone can prove me wrong on that.
Andrus
On Mar 28, 2006, at 1:11 AM, Bill Dudney wrote:
Regarding the ClassTransformer... JPA ClassTransformer is there
to presumably hide the details of how the actual enhancement is
done. By itself it won't allow you to redefine the class in the
application ClassLoader, only in your own ClassLoader. Consider
a test case:
Object object = query.getSingleResult();
assertEquals("Test1", MyPersistentClass.class.getName(),
object.getClass().getName());
assertTrue("Test2", object instanceof MyPersistentClass);
The first test succeeds, but the second one fails! Cause you'll
be checking against MyPersistentClass from the app ClassLoader,
not the enhanced MyPersistentClass from the JPA ClassLoader.
Somehow we need to make a ClassTransformer to be a "delegate"
for the app class loader to force the entire application to use
the enhanced version of the class. The only way I know of is the
instrumentation API.
My understanding is that the ClassTransformer is going to be
employed by the EntityManager to transform the classes before
returning them to the runtime.
Take a look at the comment on the bottom of page 148. The way I
read that is the ClassTransformer will be given a chance to
augment any class before making that class available to the
runtime. My understanding is that things go something like this;
Java EE Environment;
1) Container loads the persistence.xml file into a
PersistenceUnitInfo instance
2) Container creates the EntityManagerFactory implementation and
passes in the PersistenceUnitInfo
3) EntityManagerFactory (cayenne impl) adds a ClassTransformer to
the PersistenceUnitInfo
4) Container gets classes that are augmented by the ClassTransformer
JavaSE Environment;
1) Application loads JPA stuff with
Persistence.createEntityManagerFactory(String)
2) JPA runtime parses the persistence.xml file associated with
the named persistence unit
3) JPA runtime creates the EntityManagerFactory implementation
and passes in the PersistenceUnitInfo
3) EntityManagerFactory (cayenne impl) adds a ClassTransformer to
the PersistenceUnitInfo
4) JPA runtime gets classes that are augmented by the
ClassTransformer
So either way the classes that are used by the application are
augmented by the ClassTransformer. In other words the app class
loader will not be getting at the classes directly but instead
will be using the persistence unit's class loader.
So if this is true both 'Test1' and 'Test2' will work.
Thoughts?
Bill Dudney
MyFaces - http://myfaces.apache.org
Cayenne - http://incubator.apache.org/projects/cayenne.html