[
https://issues.apache.org/jira/browse/OPENJPA-1141?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Martin Dirichs updated OPENJPA-1141:
------------------------------------
Attachment: OpenJPA-Trunk_OJ1141-2.patch
I have tested patch OpenJPA-Trunk_OJ1141.patch with my application.
Unfortunately, the patch doesn't seem to eliminate the problem. There seemed to
be no difference at all.
Digging further into this issue, I could spot in the code why the patch did not
solve the problem. The patch adds a line to the bottom of
MetaDataRepository.processBuffer() to reorder entities for further processing.
Method processBuffer() is a bit strange at first view:
private List<ClassMetaData> processBuffer(ClassMetaData meta,
InheritanceOrderedMetaDataList buffer, int mode) {
// if we're already processing a metadata, just buffer this one; when
// the initial metadata finishes processing, we traverse the buffer
// and process all the others that were introduced during reentrant calls
if (!buffer.add(meta) || buffer.size() != 1)
return null;
// continually pop a metadata and process it until we run out; note
// that each processing call might place more metas in the buffer as
// one class tries to access metadata for another; also note that the
// buffer orders itself from least to most derived
ClassMetaData buffered;
List<ClassMetaData> processed = new ArrayList<ClassMetaData>(5);
while (!buffer.isEmpty()) {
buffered = buffer.peek();
buffered.resolve(mode);
processed.add(buffered);
buffer.remove(buffered);
}
// this line is added by the patch
processed = resolveFKInPKDependenciesOrdering(processed);
return processed;
}
Thus, the iteration within processBuffer() is only executed if the supplied
list of entity meta data solely contains one item, which is also supplied as
first parameter to the method. This puzzle is solved, of course, by taking into
account that the line "buffered.resolve(mode);" may lead to recursive calls to
processBuffer(), thereby growing the list of meta data while iterating over it
in the outermost call.
Note that the patch only adds a line behind the while loop. However, exceptions
similar to the one reported in this JIRA issue occur within the while loop,
during the recursion. The patch may happen to eliminate the meta data
resolution problem for the supplied test setup, it does not work for the
general case.
The root problem lies in the usage of an InheritanceOrderedMetaDataList as
buffer. This kind of list makes sure that new meta data entries put into the
list are always inserted behind any meta data entries of super classes. This is
fine, but it is not enough. If entities use other entities for their primary
key fields, this is a dependency not taken into account by the
InheritanceOrderedMetaDataList. Instead, entities not inheriting from each
other are simply ordered alphabetically when inserted into the list.
This is the real flaw of using the InheritanceOrderedMetaDataList in this
context. Since resolving the meta data of an entity is only guaranteed to work
if both super classes and entites referred to in the primary key fields are
already resolved beforehand, the usage of InheritanceOrderedMetaDataList is
error prone.
There exists another approach to remove this kind of meta data resolution
problems: Use a simple ArrayList instead of InheritanceOrderedMetaDataList. In
the process of resolving the meta data for an entity, the current code already
takes into account all possible dependencies between entities. In short,
ClassMetaData.resolveMeta() works as follows:
- resolve super class of current entity, if applicable
- resolve primary key field entities of current entity, if applicable
Both of these actions lead to calls to MetaDataRepository.processBuffer() with
the respective entity meta data before processBuffer() is finally called for
the current entity. Thus, all entities the current entity is dependent on are
put into the buffer before the current entity. A simple array list thus is
sufficient to let all entities be processed in the correct order.
I've attached a corresponding patch called OpenJPA-Trunk_OJ1141-2.patch which
implements these considerations. Although this patch removes the special logic
within MetaDataRepository introduced by the original patch, the test cases of
the original patch continue to work flawlessly as does the test suite attached
to this JIRA issue. What is more, this fix is also able to cope with the
mapping of my application, which happens to have many instances of foreign key
references in primary keys as well as sub/superclass dependencies.
> NPE at
> org.apache.openjpa.jdbc.meta.MappingInfo.mergeJoinColumn(MappingInfo.java:1400)
> ---------------------------------------------------------------------------------------
>
> Key: OPENJPA-1141
> URL: https://issues.apache.org/jira/browse/OPENJPA-1141
> Project: OpenJPA
> Issue Type: Bug
> Components: jdbc
> Affects Versions: 1.2.0
> Reporter: Yann
> Assignee: Jody Grassel
> Fix For: 1.2.2, 1.3.0, 2.0.0
>
> Attachments: ddl.sql, OpenJPA-1.2.x-OJ1141_10226009.patch,
> OpenJPA-1.3.x_OJ1141.patch, OpenJPA-Trunk_OJ1141-2.patch,
> OpenJPA-Trunk_OJ1141.patch, TestMappingProblem.zip
>
>
> We have the NPE shown below in a reproducible testcase (ZIP attached to JIRA
> ...).
> We've reduced our complex intended target domain model (about 200+ Entities)
> to a simpler model with only 3 classes which illustrate the problem: You'll
> find attached a test project with a first entity which has a a OneToMany
> (with an ElementJoinColumns, but that shouldn't matter?) to a second entity
> has a ManyToOne to a third entity. The middle entity has a Composite ID Class
> including a ManyToOne as a key, which according to
> http://openjpa.apache.org/builds/1.2.0/apache-openjpa-1.2.0/docs/manual/ref_guide_pc_oid.html#ref_guide_pc_oid_entitypk
> is supported, so this seems a bug in OpenJPA's mapping algos, somehow?
> <openjpa-1.2.1-r752877:753278 nonfatal general error>
> org.apache.openjpa.persistence.PersistenceException: null
> at
> org.apache.openjpa.kernel.QueryImpl.compileForCompilation(QueryImpl.java:610)
> at
> org.apache.openjpa.kernel.QueryImpl.compileForExecutor(QueryImpl.java:667)
> at
> org.apache.openjpa.kernel.QueryImpl.getOperation(QueryImpl.java:1492)
> at
> org.apache.openjpa.kernel.DelegatingQuery.getOperation(DelegatingQuery.java:123)
> at
> org.apache.openjpa.persistence.QueryImpl.execute(QueryImpl.java:243)
> at
> org.apache.openjpa.persistence.QueryImpl.getResultList(QueryImpl.java:294)
> at testcase.TestMappingProblem.doTest(TestMappingProblem.java:42)
> at testcase.TestMappingProblem.testIt(TestMappingProblem.java:20)
> 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 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 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: java.lang.NullPointerException
> at
> org.apache.openjpa.jdbc.meta.MappingInfo.mergeJoinColumn(MappingInfo.java:1400)
> at
> org.apache.openjpa.jdbc.meta.MappingInfo.createJoins(MappingInfo.java:1206)
> at
> org.apache.openjpa.jdbc.meta.MappingInfo.createForeignKey(MappingInfo.java:968)
> at
> org.apache.openjpa.jdbc.meta.ValueMappingInfo.getTypeJoin(ValueMappingInfo.java:104)
> at
> org.apache.openjpa.jdbc.meta.strats.RelationFieldStrategy.map(RelationFieldStrategy.java:157)
> at
> org.apache.openjpa.jdbc.meta.FieldMapping.setStrategy(FieldMapping.java:121)
> at
> org.apache.openjpa.jdbc.meta.RuntimeStrategyInstaller.installStrategy(RuntimeStrategyInstaller.java:80)
> at
> org.apache.openjpa.jdbc.meta.FieldMapping.resolveMapping(FieldMapping.java:454)
> at
> org.apache.openjpa.jdbc.meta.FieldMapping.resolve(FieldMapping.java:419)
> at
> org.apache.openjpa.jdbc.meta.ClassMapping.resolveNonRelationMappings(ClassMapping.java:869)
> at
> org.apache.openjpa.jdbc.meta.MappingRepository.prepareMapping(MappingRepository.java:339)
> at
> org.apache.openjpa.meta.MetaDataRepository.preMapping(MetaDataRepository.java:662)
> at
> org.apache.openjpa.meta.MetaDataRepository.resolve(MetaDataRepository.java:549)
> at
> org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:308)
> at
> org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:363)
> at
> org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.getClassMetaData(JPQLExpressionBuilder.java:159)
> at
> org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.resolveClassMetaData(JPQLExpressionBuilder.java:139)
> at
> org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.getCandidateMetaData(JPQLExpressionBuilder.java:225)
> at
> org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.getCandidateMetaData(JPQLExpressionBuilder.java:195)
> at
> org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.getCandidateType(JPQLExpressionBuilder.java:188)
> at
> org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder.access$600(JPQLExpressionBuilder.java:69)
> at
> org.apache.openjpa.kernel.jpql.JPQLExpressionBuilder$ParsedJPQL.populate(JPQLExpressionBuilder.java:1756)
> at
> org.apache.openjpa.kernel.jpql.JPQLParser.populate(JPQLParser.java:56)
> at
> org.apache.openjpa.kernel.ExpressionStoreQuery.populateFromCompilation(ExpressionStoreQuery.java:153)
> at
> org.apache.openjpa.kernel.QueryImpl.newCompilation(QueryImpl.java:658)
> at
> org.apache.openjpa.kernel.QueryImpl.compilationFromCache(QueryImpl.java:639)
> at
> org.apache.openjpa.kernel.QueryImpl.compileForCompilation(QueryImpl.java:605)
> ... 33 more
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.