Uploaded image for project: 'OpenJPA'
  1. OpenJPA
  2. OPENJPA-2442

java.lang.VerifyError in TestProxyManager when loading a dynamically created custom proxy class on Oracle Java 8

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 2.4.0
    • Fix Version/s: 2.4.0
    • Component/s: kernel
    • Labels:
      None
    • Environment:
      >java -version
      java version "1.8.0-ea"
      Java(TM) SE Runtime Environment (build 1.8.0-ea-b109)
      Java HotSpot(TM) 64-Bit Server VM (build 25.0-b51, mixed mode)

      Description

      While testing with Java 8 I encountered the following error noted below[1]. I'm opening this JIRA as I want to get all known issues documented.

      [1]
      <openjpa-2.3.0-SNAPSHOT-r422266:1532833M nonfatal general error> org.apache.openjpa.util.GeneralException: org.apache.openjpa.util.java$util$TreeMap$6$proxy
      at org.apache.openjpa.util.GeneratedClasses.loadBCClass(GeneratedClasses.java:71)
      at org.apache.openjpa.util.ProxyManagerImpl.getFactoryProxyMap(ProxyManagerImpl.java:407)
      at org.apache.openjpa.util.ProxyManagerImpl.copyMap(ProxyManagerImpl.java:222)
      at org.apache.openjpa.util.TestProxyManager.testCopySortedMaps(TestProxyManager.java:421)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:491)
      at junit.framework.TestCase.runTest(TestCase.java:154)
      at junit.framework.TestCase.runBare(TestCase.java:127)
      at junit.framework.TestResult$1.protect(TestResult.java:106)
      at junit.framework.TestResult.runProtected(TestResult.java:124)
      at junit.framework.TestResult.run(TestResult.java:109)
      at junit.framework.TestCase.run(TestCase.java:118)
      at junit.framework.TestSuite.runTest(TestSuite.java:208)
      at junit.framework.TestSuite.run(TestSuite.java:203)
      at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
      at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
      at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
      Caused by: java.lang.VerifyError: (class: org/apache/openjpa/util/java$util$TreeMap$6$proxy, method: remove signature: (Ljava/lang/Object;Ljava/lang/Object;)Z) Expecting to find integer on stack
      at java.lang.Class.forName0(Native Method)
      at java.lang.Class.forName(Class.java:339)
      at org.apache.openjpa.util.GeneratedClasses.loadBCClass(GeneratedClasses.java:67)
      ... 21 more

        Issue Links

          Activity

          Hide
          jira-bot ASF subversion and git services added a comment -

          Commit 1641483 from Jody Grassel in branch 'openjpa/branches/2.2.x'
          [ https://svn.apache.org/r1641483 ]

          OPENJPA-2442: java.lang.VerifyError in TestProxyManager when loading a dynamically created custom proxy class on Oracle Java 8 [JDK8]

          Show
          jira-bot ASF subversion and git services added a comment - Commit 1641483 from Jody Grassel in branch 'openjpa/branches/2.2.x' [ https://svn.apache.org/r1641483 ] OPENJPA-2442 : java.lang.VerifyError in TestProxyManager when loading a dynamically created custom proxy class on Oracle Java 8 [JDK8]
          Hide
          jira-bot ASF subversion and git services added a comment -

          Commit 1586651 from kwsutter@apache.org in branch 'openjpa/trunk'
          [ https://svn.apache.org/r1586651 ]

          OPENJPA-2442. Just using ProxyConcurrentMaps for proxying the Map methods. Since this extends ProxyMaps anyway, this is pretty safe change. This change resolves the TestProxyManager errors in openjpa-kernel when testing with Java 8 runtime. And, it doesn't affect Java 7 runtime at all. Refer to the Comments section for more details.

          Show
          jira-bot ASF subversion and git services added a comment - Commit 1586651 from kwsutter@apache.org in branch 'openjpa/trunk' [ https://svn.apache.org/r1586651 ] OPENJPA-2442 . Just using ProxyConcurrentMaps for proxying the Map methods. Since this extends ProxyMaps anyway, this is pretty safe change. This change resolves the TestProxyManager errors in openjpa-kernel when testing with Java 8 runtime. And, it doesn't affect Java 7 runtime at all. Refer to the Comments section for more details.
          Hide
          kwsutter Kevin Sutter added a comment -

          Okay, I couldn't resist... I tried a quick hack and am making tremendous progress. Since it looked like our ProxyConcurrentMaps interface was a close match, I decided to just force the use of that. Since it extends ProxyMaps and it provides the remove(key, value) method, I figured it was a close match.

          // Class<? extends ProxyMaps> mapProxyClassType =
          // ConcurrentMap.class.isAssignableFrom(type) ? ProxyConcurrentMaps.class : ProxyMaps.class;
          Class<? extends ProxyMaps> mapProxyClassType = ProxyConcurrentMaps.class; // KWS
          proxyRecognizedMethods(bc, type, mapProxyClassType, ProxyMap.class);

          With that change, all of the tests in openjpa-kernel now succeed with Java 8. Here's the updated bytecodes for the remove(key, value) method. They look much, much better with a matching before/after methods and proper processing of the return boolean value:

          public boolean remove(java.lang.Object, java.lang.Object);
          descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Z
          flags: ACC_PUBLIC
          Code:
          stack=5, locals=5, args_size=3
          0: aload_0
          1: aload_1
          2: aload_2
          3: invokestatic #134 // Method org/apache/openjpa/util/ProxyConcurrentMaps.beforeRemove:(Lorg/apache/openjpa/util/ProxyMap;Ljava/lang/Object;Ljava/lang/Object;)Z
          6: istore_3
          7: aload_0
          8: aload_1
          9: aload_2
          10: invokespecial #136 // Method org/apache/openjpa/util/TestProxyManager$CustomMap.remove:(Ljava/lang/Object;Ljava/lang/Object;)Z
          13: istore 4
          15: aload_0
          16: aload_1
          17: aload_2
          18: iload 4
          20: iload_3
          21: invokestatic #139 // Method org/apache/openjpa/util/ProxyConcurrentMaps.afterRemove:(Lorg/apache/openjpa/util/ProxyMap;Ljava/lang/Object;Ljava/lang/Object;ZZ)Z
          24: ireturn

          I'll do some more testing with this change, but so far it's looking pretty good...

          Show
          kwsutter Kevin Sutter added a comment - Okay, I couldn't resist... I tried a quick hack and am making tremendous progress. Since it looked like our ProxyConcurrentMaps interface was a close match, I decided to just force the use of that. Since it extends ProxyMaps and it provides the remove(key, value) method, I figured it was a close match. // Class<? extends ProxyMaps> mapProxyClassType = // ConcurrentMap.class.isAssignableFrom(type) ? ProxyConcurrentMaps.class : ProxyMaps.class; Class<? extends ProxyMaps> mapProxyClassType = ProxyConcurrentMaps.class; // KWS proxyRecognizedMethods(bc, type, mapProxyClassType, ProxyMap.class); With that change, all of the tests in openjpa-kernel now succeed with Java 8. Here's the updated bytecodes for the remove(key, value) method. They look much, much better with a matching before/after methods and proper processing of the return boolean value: public boolean remove(java.lang.Object, java.lang.Object); descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Z flags: ACC_PUBLIC Code: stack=5, locals=5, args_size=3 0: aload_0 1: aload_1 2: aload_2 3: invokestatic #134 // Method org/apache/openjpa/util/ProxyConcurrentMaps.beforeRemove:(Lorg/apache/openjpa/util/ProxyMap;Ljava/lang/Object;Ljava/lang/Object;)Z 6: istore_3 7: aload_0 8: aload_1 9: aload_2 10: invokespecial #136 // Method org/apache/openjpa/util/TestProxyManager$CustomMap.remove:(Ljava/lang/Object;Ljava/lang/Object;)Z 13: istore 4 15: aload_0 16: aload_1 17: aload_2 18: iload 4 20: iload_3 21: invokestatic #139 // Method org/apache/openjpa/util/ProxyConcurrentMaps.afterRemove:(Lorg/apache/openjpa/util/ProxyMap;Ljava/lang/Object;Ljava/lang/Object;ZZ)Z 24: ireturn I'll do some more testing with this change, but so far it's looking pretty good...
          Hide
          kwsutter Kevin Sutter added a comment -

          Looked at the failing tests in openjpa-kernel. Built OpenJPA with Java 7, then attempted to run the openjpa-kernel tests with Java 8 runtime. I get 3 errors. They are related to the dynamic custom proxies generated for Map attributes in an Entity. The errors are due to the fact that OpenJPA does not properly recognize the new remove(key. value) method on the Map interface. Actually, it does sort of recognize it due to the ConcurrentHashMap interface, but the existence of this remove(key, value) method just confuses our proxy generation. I don't have a complete answer yet, but I thought I would post what I have found out so that we don't have to start over the next time...

          From the call stack of one of the failures:

          testCopyMaps(org.apache.openjpa.util.TestProxyManager) Time elapsed: 0.012 sec <<< ERROR!
          <openjpa-2.4.0-SNAPSHOT-r422266:1580972M nonfatal general error> org.apache.openjpa.util.GeneralException: org.apache.openjpa.util.org$apache$openjpa$util$TestProxyManager$CustomMap$9$proxy
          at org.apache.openjpa.util.GeneratedClasses.loadBCClass(GeneratedClasses.java:72)

          You can follow the code path and see that we are attempting to generate the bytecodes right when we're trying to load the class. Eventually, we get to this portion of the code in ProxyManagerImpl.generateProxyMapBytecode():

          Class<? extends ProxyMaps> mapProxyClassType =
          ConcurrentMap.class.isAssignableFrom(type) ? ProxyConcurrentMaps.class : ProxyMaps.class;
          proxyRecognizedMethods(bc, type, mapProxyClassType, ProxyMap.class);

          This is where things go awry... Since a standard Map now supports a remove(key, value) method, we end up matching up with ProxyMaps instead of ProxyConcurrentMaps, which then generates some strange code (from the javap output):

          public boolean remove(java.lang.Object, java.lang.Object);
          descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Z
          flags: ACC_PUBLIC
          Code:
          stack=4, locals=4, args_size=3
          0: aload_0
          1: aload_1
          2: aload_2
          3: invokespecial #132 // Method org/apache/openjpa/util/TestProxyManager$CustomMap.remove:(Ljava/lang/Object;Ljava/lang/Object;)Z
          6: istore_3
          7: aload_0
          8: aload_1
          9: aload_2
          10: iload_3
          11: invokestatic #101 // Method org/apache/openjpa/util/ProxyMaps.afterRemove:(Lorg/apache/openjpa/util/ProxyMap;Ljava/lang/Object;Ljava/lang/Object;Z)Ljava/lang/Object;
          14: ireturn

          There is no matching beforeRemove() method invoked – which should be a standard practice of having matching before/after calls. And, the afterRemove() method that is invoked on ProxyMaps really doesn't match the expected processing of the remove(key, value) method. Looking at our code a bit, it looks like the use of the ProxyConcurrentMaps interface would have been a better match. At least the remove(key, value) method is already recognized...

          Anyway, that's what I have so far. I don't know if this is simply a matter of including processing for remove(key, value) in ProxyMaps, or if there's something more involved than that. Need more time to experiment and I have run out of that for the time being... Good luck to the next player.

          Show
          kwsutter Kevin Sutter added a comment - Looked at the failing tests in openjpa-kernel. Built OpenJPA with Java 7, then attempted to run the openjpa-kernel tests with Java 8 runtime. I get 3 errors. They are related to the dynamic custom proxies generated for Map attributes in an Entity. The errors are due to the fact that OpenJPA does not properly recognize the new remove(key. value) method on the Map interface. Actually, it does sort of recognize it due to the ConcurrentHashMap interface, but the existence of this remove(key, value) method just confuses our proxy generation. I don't have a complete answer yet, but I thought I would post what I have found out so that we don't have to start over the next time... From the call stack of one of the failures: testCopyMaps(org.apache.openjpa.util.TestProxyManager) Time elapsed: 0.012 sec <<< ERROR! <openjpa-2.4.0-SNAPSHOT-r422266:1580972M nonfatal general error> org.apache.openjpa.util.GeneralException: org.apache.openjpa.util.org$apache$openjpa$util$TestProxyManager$CustomMap$9$proxy at org.apache.openjpa.util.GeneratedClasses.loadBCClass(GeneratedClasses.java:72) You can follow the code path and see that we are attempting to generate the bytecodes right when we're trying to load the class. Eventually, we get to this portion of the code in ProxyManagerImpl.generateProxyMapBytecode(): Class<? extends ProxyMaps> mapProxyClassType = ConcurrentMap.class.isAssignableFrom(type) ? ProxyConcurrentMaps.class : ProxyMaps.class; proxyRecognizedMethods(bc, type, mapProxyClassType, ProxyMap.class); This is where things go awry... Since a standard Map now supports a remove(key, value) method, we end up matching up with ProxyMaps instead of ProxyConcurrentMaps, which then generates some strange code (from the javap output): public boolean remove(java.lang.Object, java.lang.Object); descriptor: (Ljava/lang/Object;Ljava/lang/Object;)Z flags: ACC_PUBLIC Code: stack=4, locals=4, args_size=3 0: aload_0 1: aload_1 2: aload_2 3: invokespecial #132 // Method org/apache/openjpa/util/TestProxyManager$CustomMap.remove:(Ljava/lang/Object;Ljava/lang/Object;)Z 6: istore_3 7: aload_0 8: aload_1 9: aload_2 10: iload_3 11: invokestatic #101 // Method org/apache/openjpa/util/ProxyMaps.afterRemove:(Lorg/apache/openjpa/util/ProxyMap;Ljava/lang/Object;Ljava/lang/Object;Z)Ljava/lang/Object; 14: ireturn There is no matching beforeRemove() method invoked – which should be a standard practice of having matching before/after calls. And, the afterRemove() method that is invoked on ProxyMaps really doesn't match the expected processing of the remove(key, value) method. Looking at our code a bit, it looks like the use of the ProxyConcurrentMaps interface would have been a better match. At least the remove(key, value) method is already recognized... Anyway, that's what I have so far. I don't know if this is simply a matter of including processing for remove(key, value) in ProxyMaps, or if there's something more involved than that. Need more time to experiment and I have run out of that for the time being... Good luck to the next player.
          Hide
          curtisr7 Rick Curtis added a comment -

          This same-ish error is encountered many, many(100+) times when running through the tests in openjpa-persistence-jdbc.

          Show
          curtisr7 Rick Curtis added a comment - This same-ish error is encountered many, many(100+) times when running through the tests in openjpa-persistence-jdbc.

            People

            • Assignee:
              kwsutter Kevin Sutter
              Reporter:
              curtisr7 Rick Curtis
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development