OpenJPA
  1. OpenJPA
  2. OPENJPA-1736

Mappings with foreign keys as identity fields sometimes not resolved correctly

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.0.0
    • Fix Version/s: 2.1.0
    • Component/s: jdbc
    • Labels:
      None
    • Patch Info:
      Patch Available

      Description

      This is a follow-up issue of OPENJPA-1141. The solution developed for that issue only handled some aspects of an underlying greater problem with OpenJPAs mapping algorithm. This algorithm may fail under certain circumstances involving foreign keys used as identity fields in other entities. A patch with a test case illustrating this problem is attached to this issue. The problem can probably show up with different exceptions. However, the stack trace for the supplied test case is as follows:

      testEntityAsIdentityField001(org.apache.openjpa.persistence.identity.entityasidentity2.TestEntityAsIdentityFields2) Time elapsed: 1.656 sec <<< ERROR!
      <openjpa-2.0.0-r422266:935683M fatal user error> org.apache.openjpa.persistence.ArgumentException: Errors encountered while resolving metadata. See nested exceptions for details.
      at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:642)
      at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:385)
      at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:358)
      at org.apache.openjpa.meta.MetaDataRepository.resolveMeta(MetaDataRepository.java:688)
      at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:617)
      at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:385)
      at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:358)
      at org.apache.openjpa.jdbc.meta.MappingRepository.getMapping(MappingRepository.java:355)
      at org.apache.openjpa.jdbc.meta.MappingTool.getMapping(MappingTool.java:679)
      at org.apache.openjpa.jdbc.meta.MappingTool.buildSchema(MappingTool.java:751)
      at org.apache.openjpa.jdbc.meta.MappingTool.run(MappingTool.java:649)
      at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:149)
      at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.synchronizeMappings(JDBCBrokerFactory.java:159)
      at org.apache.openjpa.jdbc.kernel.JDBCBrokerFactory.newBrokerImpl(JDBCBrokerFactory.java:117)
      at org.apache.openjpa.kernel.AbstractBrokerFactory.newBroker(AbstractBrokerFactory.java:199)
      at org.apache.openjpa.kernel.DelegatingBrokerFactory.newBroker(DelegatingBrokerFactory.java:156)
      at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:213)
      at org.apache.openjpa.persistence.EntityManagerFactoryImpl.createEntityManager(EntityManagerFactoryImpl.java:151)
      at org.apache.openjpa.persistence.identity.entityasidentity2.TestEntityAsIdentityFields2.testEntityAsIdentityField001(TestEntityAsIdentityFields2.java:16)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at junit.framework.TestCase.runTest(TestCase.java:154)
      at org.apache.openjpa.persistence.test.AbstractPersistenceTestCase.runTest(AbstractPersistenceTestCase.java:516)
      at junit.framework.TestCase.runBare(TestCase.java:127)
      at org.apache.openjpa.persistence.test.AbstractPersistenceTestCase.runBare(AbstractPersistenceTestCase.java:503)
      at org.apache.openjpa.persistence.test.AbstractPersistenceTestCase.runBare(AbstractPersistenceTestCase.java:479)
      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 org.apache.openjpa.persistence.test.AbstractPersistenceTestCase.run(AbstractPersistenceTestCase.java:179)
      at junit.framework.TestSuite.runTest(TestSuite.java:208)
      at junit.framework.TestSuite.run(TestSuite.java:203)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:213)
      at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
      at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
      at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345)
      at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)
      Caused by: <openjpa-2.0.0-r422266:935683M fatal user error> org.apache.openjpa.persistence.ArgumentException: The id class specified by type "class org.apache.openjpa.persistence.identity.entityasidentity2.Attendance" does not match the primary key fields of the class. Make sure your identity class has the same primary keys as your persistent type, including pk field types. Mismatched property: "student"
      at org.apache.openjpa.meta.ClassMetaData.validateAppIdClassPKs(ClassMetaData.java:2205)
      at org.apache.openjpa.meta.ClassMetaData.validateAppIdClass(ClassMetaData.java:2079)
      at org.apache.openjpa.meta.ClassMetaData.validateIdentity(ClassMetaData.java:2015)
      at org.apache.openjpa.meta.ClassMetaData.validateMeta(ClassMetaData.java:1927)
      at org.apache.openjpa.meta.ClassMetaData.resolve(ClassMetaData.java:1788)
      at org.apache.openjpa.meta.MetaDataRepository.processBuffer(MetaDataRepository.java:790)
      at org.apache.openjpa.meta.MetaDataRepository.resolveMeta(MetaDataRepository.java:693)
      at org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:617)
      ... 48 more

      A proposed solution to this issue is given below.

      1. OpenJPA-2.0.0_OJ1736.testcase.patch
        5 kB
        Martin Dirichs
      2. OpenJPA-2.0.0_OJ1736.patch
        19 kB
        Martin Dirichs

        Issue Links

          Activity

          Hide
          Martin Dirichs added a comment -

          File OpenJPA-2.0.0_OJ1736.testcase.patch contains a test case which can be applied to the OpenJPA source and then run.

          Show
          Martin Dirichs added a comment - File OpenJPA-2.0.0_OJ1736.testcase.patch contains a test case which can be applied to the OpenJPA source and then run.
          Hide
          Martin Dirichs added a comment -

          File OpenJPA-2.0.0_OJ1736.patch contains a proposed fix for this issue.

          Basically, the patch removes the changes done for OPENJPA-1141 and replaces the InheritanceOrderedMetaDataList used in MetaDataRepository.processBuffer with a simple ArrayList<MetaData>. The assumptions accompanying this patch are:

          • The fix for OPENJPA-1141, which consisted of an elaborate reordering of metadata classes at the end of method processBuffer, does not work in all cases, see attached test case. Reason: the reordering is done too late, things may go wrong earlier in the middle of method processBuffer.
          • There is no need to use complicated structures such as InheritanceOrderedMetaDataList, as the recursive resolution method implemented by processBuffer already ensures that entities that need to be resolved before another entity may be resolved, are put into the buffer after the entity that depends on them. Thus it suffices to just process the meta data instances accumulated in the buffer in a last-in-first-out fashion.

          To be honest, I am not 100% sure that the second assumption is always right. There might be convoluted cases of complex entity dependencies where this assumption is no longer valid. However, the current approach based on InheritanceOrderedMetaDataList is much worse and leads to errors quite soon (the attached test case only needs 4 entities to trigger the error). A patched version of OpenJPA runs fine with our application of ~40 entities, quite a few of them depending on other entities (inheritance as well as identities based on foreign keys). With the original OpenJPA, this problem already faced at around 20 entities with no workaround possible.

          If it helps the adoption of this patch, I could assemble more complex mappings to see whether the patch continues to work or not. I am also willing to supply patches for the current trunk version as well as the 1.2-branch, if this is requested.

          Show
          Martin Dirichs added a comment - File OpenJPA-2.0.0_OJ1736.patch contains a proposed fix for this issue. Basically, the patch removes the changes done for OPENJPA-1141 and replaces the InheritanceOrderedMetaDataList used in MetaDataRepository.processBuffer with a simple ArrayList<MetaData>. The assumptions accompanying this patch are: The fix for OPENJPA-1141 , which consisted of an elaborate reordering of metadata classes at the end of method processBuffer, does not work in all cases, see attached test case. Reason: the reordering is done too late, things may go wrong earlier in the middle of method processBuffer. There is no need to use complicated structures such as InheritanceOrderedMetaDataList, as the recursive resolution method implemented by processBuffer already ensures that entities that need to be resolved before another entity may be resolved, are put into the buffer after the entity that depends on them. Thus it suffices to just process the meta data instances accumulated in the buffer in a last-in-first-out fashion. To be honest, I am not 100% sure that the second assumption is always right. There might be convoluted cases of complex entity dependencies where this assumption is no longer valid. However, the current approach based on InheritanceOrderedMetaDataList is much worse and leads to errors quite soon (the attached test case only needs 4 entities to trigger the error). A patched version of OpenJPA runs fine with our application of ~40 entities, quite a few of them depending on other entities (inheritance as well as identities based on foreign keys). With the original OpenJPA, this problem already faced at around 20 entities with no workaround possible. If it helps the adoption of this patch, I could assemble more complex mappings to see whether the patch continues to work or not. I am also willing to supply patches for the current trunk version as well as the 1.2-branch, if this is requested.
          Hide
          Catalina Wei added a comment -

          Thanks to Martin, your patch has been committed in r987772 (trunk), and r987773 (2.0.x).

          Show
          Catalina Wei added a comment - Thanks to Martin, your patch has been committed in r987772 (trunk), and r987773 (2.0.x).
          Hide
          Catalina Wei added a comment -

          Back out changes to 2.0.x branch.
          Updates to maintenance stream 2.0.x must get approval from Michael Dick.

          Show
          Catalina Wei added a comment - Back out changes to 2.0.x branch. Updates to maintenance stream 2.0.x must get approval from Michael Dick.
          Hide
          Michael Dick added a comment -

          Closing issues which have been resolved for some time. If the problem persists, please reopen.

          Show
          Michael Dick added a comment - Closing issues which have been resolved for some time. If the problem persists, please reopen.

            People

            • Assignee:
              Catalina Wei
              Reporter:
              Martin Dirichs
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development