Re: JPA and class enhancers

From: Andrus Adamchik (andru..bjectstyle.org)
Date: Tue Mar 28 2006 - 02:05:13 EST

  • Next message: Andrus Adamchik: "Re: RoR'ing Cayenne"

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



    This archive was generated by hypermail 2.0.0 : Tue Mar 28 2006 - 02:05:39 EST