Geronimo
  1. Geronimo
  2. GERONIMO-5553

Fail to enchance entities on Geronimo

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Invalid
    • Affects Version/s: 3.0.0
    • Fix Version/s: 3.0.0
    • Component/s: persistence
    • Security Level: public (Regular issues)
    • Labels:
      None
    • Environment:

      OS:win xp
      Geronimo :3.0 20100824 build

      Description

      I tried to deploy a simple jpa sample on geronimo.But when persist data into database.
      Following exception will occur.

      <openjpa-2.0.0-r422266:935683 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: Attempt to cast instance "org.apache.sample.entities.Book@97781f" to PersistenceCapable failed. Ensure that it has been enhanced.
      FailedObject: org.apache.sample.entities.Book@97781f

        Issue Links

          Activity

          Show
          Han Hong Fang added a comment - Related JIRA: https://issues.apache.org/jira/browse/GERONIMODEVTOOLS-671
          Hide
          Lu Jiang added a comment -

          This is the simple jpa demo I used for test.

          Show
          Lu Jiang added a comment - This is the simple jpa demo I used for test.
          Hide
          Donald Woods added a comment -

          I decompiled your org.apache.sample.entities.Book.class and did not see that it had been enhanced.

          In OpenJPA 2.0, we have turned RuntimeUnenhancedClasses off/unsupported by default (it was enabled in 1.0 and 1.2) -
          http://openjpa.apache.org/builds/2.0.0/apache-openjpa-2.0.0/docs/manual/manual.html#openjpa.RuntimeUnenhancedClasses

          To enable runtime enhancement (which we strongly discourage for production applications), you need to update your persistence.xml to set the following property -
          <properties>
          <property name="openjpa.RuntimeUnenhancedClasses" value="supported"/>
          . . .
          </properties>

          The better solution, is to use build time enhancement, which can be done via ANT, Maven plugin or Eclipse plugin -
          http://openjpa.apache.org/entity-enhancement.html

          Show
          Donald Woods added a comment - I decompiled your org.apache.sample.entities.Book.class and did not see that it had been enhanced. In OpenJPA 2.0, we have turned RuntimeUnenhancedClasses off/unsupported by default (it was enabled in 1.0 and 1.2) - http://openjpa.apache.org/builds/2.0.0/apache-openjpa-2.0.0/docs/manual/manual.html#openjpa.RuntimeUnenhancedClasses To enable runtime enhancement (which we strongly discourage for production applications), you need to update your persistence.xml to set the following property - <properties> <property name="openjpa.RuntimeUnenhancedClasses" value="supported"/> . . . </properties> The better solution, is to use build time enhancement, which can be done via ANT, Maven plugin or Eclipse plugin - http://openjpa.apache.org/entity-enhancement.html
          Hide
          Kevan Miller added a comment -

          Pre-compilation or special persistence.xml properties should not be required in this case. This sounds like a Geronimo problem which needs to be fixed. If Book.class is not being dynamically enhanced, then seems like something needs to be changed within Geronimo so that enhancement occurs.

          Show
          Kevan Miller added a comment - Pre-compilation or special persistence.xml properties should not be required in this case. This sounds like a Geronimo problem which needs to be fixed. If Book.class is not being dynamically enhanced, then seems like something needs to be changed within Geronimo so that enhancement occurs.
          Hide
          Donald Woods added a comment -

          Agree, the Javaagent code should work no matter what RuntimeUnenhancedClasses is set to.

          After more digging, in 2.1.5 we used -
          JAVA_AGENT_JAR="$GERONIMO_HOME/bin/jpa.jar"
          but in 3.0, we are using -
          JAVA_AGENT_JAR="$GERONIMO_HOME/lib/agent/transformer.jar"
          and there is no jpa.jar anywhere to be found.....

          So, the real question is, where did jpa.jar go and how do we register OpenJPA with
          framework/modules/geronimo-transformer/src/main/java/org/apache/geronimo/transformer/TransformerAgent.java ?

          Show
          Donald Woods added a comment - Agree, the Javaagent code should work no matter what RuntimeUnenhancedClasses is set to. After more digging, in 2.1.5 we used - JAVA_AGENT_JAR="$GERONIMO_HOME/bin/jpa.jar" but in 3.0, we are using - JAVA_AGENT_JAR="$GERONIMO_HOME/lib/agent/transformer.jar" and there is no jpa.jar anywhere to be found..... So, the real question is, where did jpa.jar go and how do we register OpenJPA with framework/modules/geronimo-transformer/src/main/java/org/apache/geronimo/transformer/TransformerAgent.java ?
          Hide
          Donald Woods added a comment -

          Both of these are registering transformers -
          openjpa2/geronimo-aries-jpa/src/main/java/org/apache/geronimo/aries/jpa/GeronimoPersistenceUnitInfo.java
          openjpa2/geronimo-persistence-jpa20/src/main/java/org/apache/geronimo/persistence/PersistenceUnitGBean.java

          So, are all WAR files being turned into WAB files and run as OSGi bundles in 3.0? If so, then using JPA in WAR files is going to require Aries and the geronimo-aries-jpa code, which knows about bundle context, while the normal geronimo-persistence-jpa20 code has no knowledge of bundles and how to access their classloaders???

          Show
          Donald Woods added a comment - Both of these are registering transformers - openjpa2/geronimo-aries-jpa/src/main/java/org/apache/geronimo/aries/jpa/GeronimoPersistenceUnitInfo.java openjpa2/geronimo-persistence-jpa20/src/main/java/org/apache/geronimo/persistence/PersistenceUnitGBean.java So, are all WAR files being turned into WAB files and run as OSGi bundles in 3.0? If so, then using JPA in WAR files is going to require Aries and the geronimo-aries-jpa code, which knows about bundle context, while the normal geronimo-persistence-jpa20 code has no knowledge of bundles and how to access their classloaders???
          Hide
          Kevan Miller added a comment -

          jpa.jar didn't contain any classes. Instead, MANIFEST.MF pointed to lib/geronimo-transformer-2.1.6.jar

          So, I believe same basic structure is used in 2.x and 3.0. The OpenJPA javaagent still needs to get registered with the TransformerAgent. That may not be working properly in 3.0. Or there's some more fundamental issue...

          Show
          Kevan Miller added a comment - jpa.jar didn't contain any classes. Instead, MANIFEST.MF pointed to lib/geronimo-transformer-2.1.6.jar So, I believe same basic structure is used in 2.x and 3.0. The OpenJPA javaagent still needs to get registered with the TransformerAgent. That may not be working properly in 3.0. Or there's some more fundamental issue...
          Hide
          Jarek Gawor added a comment -

          OpenJPA agent gets registered with TransformerAgent via PersistenceUnitGBean$PersistenceUnitInfoImpl.addTransformer(). That method should be called by OpenJPA and it was the last time I looked at the code...

          Show
          Jarek Gawor added a comment - OpenJPA agent gets registered with TransformerAgent via PersistenceUnitGBean$PersistenceUnitInfoImpl.addTransformer(). That method should be called by OpenJPA and it was the last time I looked at the code...
          Hide
          Jarek Gawor added a comment -

          Aries JPA code only kicks in if a war file is deployed as a wab, i.e. deployed as part of eba or installed via osgi:install webbundle://<war file> command.
          I assume in this case the war file is deployed as a regular java ee application. So no need to worry about Aries JPA code.

          Show
          Jarek Gawor added a comment - Aries JPA code only kicks in if a war file is deployed as a wab, i.e. deployed as part of eba or installed via osgi:install webbundle://<war file> command. I assume in this case the war file is deployed as a regular java ee application. So no need to worry about Aries JPA code.
          Hide
          Rick McGuire added a comment -

          Could the solution to this be as simple as adding openjpa.RuntimeUnenhancedClasses supported to the property bundle we use when calling createContainerEntityManagerFactory()? A cursory look at the openjpa code seems to suggest this is supported both in property and xml form.

          Show
          Rick McGuire added a comment - Could the solution to this be as simple as adding openjpa.RuntimeUnenhancedClasses supported to the property bundle we use when calling createContainerEntityManagerFactory()? A cursory look at the openjpa code seems to suggest this is supported both in property and xml form.
          Hide
          Donald Woods added a comment -

          I checked with Jeremy on the OpenJPA team yesterday and he agreed that the openjpa.RuntimeUnenhancedClasses property is ignored for the javaagent code and only used for dynamic runtime enhancement (subclassing), so setting that value in the EMF Map should not be required and is discouraged, as we tell OpenJPA users all the time NOT to use dynamic runtime enhancement.

          For the javaagent, classLoadEnhancement=true is the default, which controls whether OpenJPA load-time class enhancement should be available in this JVM execution.

          Starting in OpenJPA 2.0 - If a javaagent is not provided via the command line and OpenJPA is running on the Sun 1.6 SDK or IBM 1.6 JDK (SR8+), OpenJPA will attempt to dynamically load the runtime Enhancer. This support is provided as an ease of use feature and it is not recommended for use in a production system. Setting the property openjpa.DynamicEnhancementAgent to false will disable this function.

          When then dynamic enhancer is loaded, the following informational message is logged:
          [java] jpa.enhancement INFO [main] openjpa.Runtime - OpenJPA dynamically loaded the class enhancer. Any classes that were not enhanced at build time will be enhanced when they are loaded by the JVM.

          So, is another module (like a deployer, annotation scanner or Tomcat) possibly loading the classes before the OpenJPA GBean is being loaded and having a chance to register the TransformerAgent?

          Show
          Donald Woods added a comment - I checked with Jeremy on the OpenJPA team yesterday and he agreed that the openjpa.RuntimeUnenhancedClasses property is ignored for the javaagent code and only used for dynamic runtime enhancement (subclassing), so setting that value in the EMF Map should not be required and is discouraged, as we tell OpenJPA users all the time NOT to use dynamic runtime enhancement. For the javaagent, classLoadEnhancement=true is the default, which controls whether OpenJPA load-time class enhancement should be available in this JVM execution. Starting in OpenJPA 2.0 - If a javaagent is not provided via the command line and OpenJPA is running on the Sun 1.6 SDK or IBM 1.6 JDK (SR8+), OpenJPA will attempt to dynamically load the runtime Enhancer. This support is provided as an ease of use feature and it is not recommended for use in a production system. Setting the property openjpa.DynamicEnhancementAgent to false will disable this function. When then dynamic enhancer is loaded, the following informational message is logged: [java] jpa.enhancement INFO [main] openjpa.Runtime - OpenJPA dynamically loaded the class enhancer. Any classes that were not enhanced at build time will be enhanced when they are loaded by the JVM. So, is another module (like a deployer, annotation scanner or Tomcat) possibly loading the classes before the OpenJPA GBean is being loaded and having a chance to register the TransformerAgent?
          Hide
          Donald Woods added a comment -

          In geronimo-transformer, the TransformerWrapper class is commented out and no longer used, but geronimo-persistence-jpa20 and geronimo-aries-jpa contains its own implementation of TransformerWrapper, which only calls the transformer if the provided classloader is an instance of BundleReference? Is that the right behavior for geronimo-persistence-jpa20 for a WAR case, where it is not a Bundle? Seems okay for the Aries case...

          public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
          if (loader instanceof BundleReference && ((BundleReference) loader).getBundle() == bundle) {
          try

          { return classTransformer.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); }

          catch (IllegalClassFormatException e)

          { throw e; }

          catch (RuntimeException e)

          { return null; }

          }
          return null;
          }

          Show
          Donald Woods added a comment - In geronimo-transformer, the TransformerWrapper class is commented out and no longer used, but geronimo-persistence-jpa20 and geronimo-aries-jpa contains its own implementation of TransformerWrapper, which only calls the transformer if the provided classloader is an instance of BundleReference? Is that the right behavior for geronimo-persistence-jpa20 for a WAR case, where it is not a Bundle? Seems okay for the Aries case... public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { if (loader instanceof BundleReference && ((BundleReference) loader).getBundle() == bundle) { try { return classTransformer.transform(loader, className, classBeingRedefined, protectionDomain, classfileBuffer); } catch (IllegalClassFormatException e) { throw e; } catch (RuntimeException e) { return null; } } return null; }
          Hide
          Jarek Gawor added a comment -

          First, let me correct something. Aries JPA kicks in when a bundle with Meta-Persistence header is deployed. So it's not really about application being deployed as a wab. Either way, however, Aries JPA will not be used when deploying a regular Java EE web application.

          Second, everything is turned into a bundle during deployment so even a war module should have a classloader that implements the BundleReference interface. But this is probably good place to put a break point to see if transform() is being called.

          Third, I know that JPA runtime enhancement is working fine in Geronimo for Aries applications at least because the testsuites/aries-testsuites/jpa tests are passing.

          Show
          Jarek Gawor added a comment - First, let me correct something. Aries JPA kicks in when a bundle with Meta-Persistence header is deployed. So it's not really about application being deployed as a wab. Either way, however, Aries JPA will not be used when deploying a regular Java EE web application. Second, everything is turned into a bundle during deployment so even a war module should have a classloader that implements the BundleReference interface. But this is probably good place to put a break point to see if transform() is being called. Third, I know that JPA runtime enhancement is working fine in Geronimo for Aries applications at least because the testsuites/aries-testsuites/jpa tests are passing.
          Hide
          Donald Woods added a comment -

          OK, so this dual personality is really confusing... Looking back at ARIES-320, you added and them removed code to enable the javaagent support and instead in geronimo-aries-jpa created "GeronimoManagedPersistenceUnitInfoFactory extends ManagedPersistenceUnitInfoFactoryImpl". How did this enable the javaagent for Aries apps???

          Guess I'm wondering, if the app is being loaded as a bundle, is OpenJPA being loaded as a bundle? We have tons of places in OpenJPA where we're looking up classloaders, but only one place (broker factory creation) that we try to use the bundle context if available (which was OPENJPA-1491 for Aries.) So, if the OpenJPA transformer uses the bundle context, what is the runtime using and are we seeing two copies of the class, one enhanced and one not....?

          Show
          Donald Woods added a comment - OK, so this dual personality is really confusing... Looking back at ARIES-320 , you added and them removed code to enable the javaagent support and instead in geronimo-aries-jpa created "GeronimoManagedPersistenceUnitInfoFactory extends ManagedPersistenceUnitInfoFactoryImpl". How did this enable the javaagent for Aries apps??? Guess I'm wondering, if the app is being loaded as a bundle, is OpenJPA being loaded as a bundle? We have tons of places in OpenJPA where we're looking up classloaders, but only one place (broker factory creation) that we try to use the bundle context if available (which was OPENJPA-1491 for Aries.) So, if the OpenJPA transformer uses the bundle context, what is the runtime using and are we seeing two copies of the class, one enhanced and one not....?
          Hide
          Jarek Gawor added a comment -

          Once again, the Aries JPA is not used in this case. So no need to worry about it. But if you are interested, this works in exactly the same way as it works for regular Java EE apps. OpenJPA calls PersistenceUntInfo.addTransfomer() which then registers the transformer with the agent which later on causes the enhancement to be done.

          Everything is a bundle in Geronimo 3.0. I'm pretty sure the PU provides the classloader it wants to use via PersistenceUnitInfo.getClassLoader().

          Show
          Jarek Gawor added a comment - Once again, the Aries JPA is not used in this case. So no need to worry about it. But if you are interested, this works in exactly the same way as it works for regular Java EE apps. OpenJPA calls PersistenceUntInfo.addTransfomer() which then registers the transformer with the agent which later on causes the enhancement to be done. Everything is a bundle in Geronimo 3.0. I'm pretty sure the PU provides the classloader it wants to use via PersistenceUnitInfo.getClassLoader().
          Hide
          Lin Sun added a comment -

          Hi

          After some initial investigate, it turned out to be a user error in persistence.xml. The class should be:

          <class>org.apache.sample.entities.Book</class>

          while the one in the attached war has it configured as org.apache.geronimo.sample.entities.Book

          This is causing the entity enhancement error as it was tried to enhance the wrong class.

          After I made the above change, I am not seeing the entity didn't enhance error.

          P.S. This user case (a PU in war file) has to be a war file. If it is a WAB, it won't work, as the aries JPA doesn't support PU in WAB.

          Please advise if this answer is satisfactory. If so, you may close the bug.

          Thanks

          Lin

          Show
          Lin Sun added a comment - Hi After some initial investigate, it turned out to be a user error in persistence.xml. The class should be: <class>org.apache.sample.entities.Book</class> while the one in the attached war has it configured as org.apache.geronimo.sample.entities.Book This is causing the entity enhancement error as it was tried to enhance the wrong class. After I made the above change, I am not seeing the entity didn't enhance error. P.S. This user case (a PU in war file) has to be a war file. If it is a WAB, it won't work, as the aries JPA doesn't support PU in WAB. Please advise if this answer is satisfactory. If so, you may close the bug. Thanks Lin
          Hide
          Donald Woods added a comment -

          Thanks Lin. I missed that.
          But, this was unexpected behavior for OpenJPA due to Geronimo using the javaagent, which only enhances the classes listed in the persistence.xml whereas the dynamic enhancer will find other classes to enhance unless <exclude-unlisted-classes> is specified. If no classes are specified, then all of the classes will get enhanced whether the dynamic or javaagent methods are used. So, we have a difference in enhancement behavior here....

          Show
          Donald Woods added a comment - Thanks Lin. I missed that. But, this was unexpected behavior for OpenJPA due to Geronimo using the javaagent, which only enhances the classes listed in the persistence.xml whereas the dynamic enhancer will find other classes to enhance unless <exclude-unlisted-classes> is specified. If no classes are specified, then all of the classes will get enhanced whether the dynamic or javaagent methods are used. So, we have a difference in enhancement behavior here....
          Hide
          Rick McGuire added a comment -

          What criteria would be used by the dynamic enhancer to discover and enhance this class? If it's not being done by the javaagent, when would that discovery be performed?

          Show
          Rick McGuire added a comment - What criteria would be used by the dynamic enhancer to discover and enhance this class? If it's not being done by the javaagent, when would that discovery be performed?
          Hide
          Rick McGuire added a comment -

          I did a little experimentation on this, and I believe this is probably working the way it was intended. Debugging the geronimo transformer wrapper, I'm seeing the transformer getting called on the Book class and all other classes of this application, so it looks like the javaagent hook is working correctly.

          I deployed this application on 2.2 to see what would happen, and it gave a similar (but different) error, which leads me to believe this really can be closed:

          <openjpa-1.2.1-r752877:753278 fatal user error> org.apache.openjpa.persistence.A
          rgumentException: No metadata was found for type "class org.apache.sample.entiti
          es.Book". The class does not appear in the list of persistent types: [org.apache
          .geronimo.sample.entities.Book].
          at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataReposi
          tory.java:303)
          at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2426)
          at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2280)
          at org.apache.openjpa.kernel.DelegatingBroker.persist(DelegatingBroker.j
          ava:1021)
          at org.apache.openjpa.persistence.EntityManagerImpl.persist(EntityManage
          rImpl.java:645)
          at org.apache.sample.bean.Facade.createBook(Facade.java:21)
          at org.apache.sample.action.AddBook.doPost(AddBook.java:48)
          at org.apache.sample.action.AddBook.doGet(AddBook.java:33)
          at javax.servlet.http.HttpServlet.service(HttpServlet.java:693)
          at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)

          Show
          Rick McGuire added a comment - I did a little experimentation on this, and I believe this is probably working the way it was intended. Debugging the geronimo transformer wrapper, I'm seeing the transformer getting called on the Book class and all other classes of this application, so it looks like the javaagent hook is working correctly. I deployed this application on 2.2 to see what would happen, and it gave a similar (but different) error, which leads me to believe this really can be closed: <openjpa-1.2.1-r752877:753278 fatal user error> org.apache.openjpa.persistence.A rgumentException: No metadata was found for type "class org.apache.sample.entiti es.Book". The class does not appear in the list of persistent types: [org.apache .geronimo.sample.entities.Book]. at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataReposi tory.java:303) at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2426) at org.apache.openjpa.kernel.BrokerImpl.persist(BrokerImpl.java:2280) at org.apache.openjpa.kernel.DelegatingBroker.persist(DelegatingBroker.j ava:1021) at org.apache.openjpa.persistence.EntityManagerImpl.persist(EntityManage rImpl.java:645) at org.apache.sample.bean.Facade.createBook(Facade.java:21) at org.apache.sample.action.AddBook.doPost(AddBook.java:48) at org.apache.sample.action.AddBook.doGet(AddBook.java:33) at javax.servlet.http.HttpServlet.service(HttpServlet.java:693) at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
          Hide
          Rick McGuire added a comment -

          The application contained a user error, but the openjpa message significantly affected how long it took to solve the problem because it steered everybody away from the root cause. The 1.x version gave better resolution suggestions.

          Show
          Rick McGuire added a comment - The application contained a user error, but the openjpa message significantly affected how long it took to solve the problem because it steered everybody away from the root cause. The 1.x version gave better resolution suggestions.
          Hide
          Donald Woods added a comment -

          Reply to the 8/30 questions about enhancer, which dup my 8/27 comments.... When a list of classes is handed to the javaagent, then it will only enhance those classes, but when no class list is given it will discover all classes to enhance. When the 1.6 JVM's Attach API is used (new in OpenJPA 2.0) to dynamically load the OpenJPA enhancer agent, then the class list is used AND any other classes to enhance are discovered unless <exclude-unlisted-classes> is specified in the PU.

          So, I'll opened OPENJPA-1780 to request that the javaagent behave the same as the dynamic loader....

          Show
          Donald Woods added a comment - Reply to the 8/30 questions about enhancer, which dup my 8/27 comments.... When a list of classes is handed to the javaagent, then it will only enhance those classes, but when no class list is given it will discover all classes to enhance. When the 1.6 JVM's Attach API is used (new in OpenJPA 2.0) to dynamically load the OpenJPA enhancer agent, then the class list is used AND any other classes to enhance are discovered unless <exclude-unlisted-classes> is specified in the PU. So, I'll opened OPENJPA-1780 to request that the javaagent behave the same as the dynamic loader....

            People

            • Assignee:
              Rick McGuire
              Reporter:
              Lu Jiang
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development