Community
Participate
Working Groups
Build Identifier: I will attach 5 java files that reproduce this defect 100% of the time. In short: Model: AllYourBase----------OneToMany-------Prop | ^- SubThing extends AllYourBase Query: SELECT distinct e FROM AllYourBase e JOIN FETCH e.props WHERE e.id.id = :p AND e.id.mdrProduct = :q AND e.id.mdrProdInstance = :r Defect: if statement shouldPrepare is true, running this query once works. However, subsequent executions always result in NPE: java.lang.NullPointerException at org.eclipse.persistence.descriptors.InheritancePolicy.selectAllRowUsingDefaultMultipleTableSubclassRead(InheritancePolicy.java:1376) at org.eclipse.persistence.descriptors.InheritancePolicy.selectAllRowUsingMultipleTableSubclassRead(InheritancePolicy.java:1417) at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.selectAllRows(ExpressionQueryMechanism.java:2567) at org.eclipse.persistence.queries.ReadAllQuery.executeObjectLevelReadQuery(ReadAllQuery.java:420) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeDatabaseQuery(ObjectLevelReadQuery.java:1081) at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:844) at org.eclipse.persistence.queries.ObjectLevelReadQuery.execute(ObjectLevelReadQuery.java:1040) at org.eclipse.persistence.queries.ReadAllQuery.execute(ReadAllQuery.java:392) at org.eclipse.persistence.queries.ObjectLevelReadQuery.executeInUnitOfWork(ObjectLevelReadQuery.java:1128) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2871) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1516) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1498) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1463) at org.eclipse.persistence.internal.jpa.EJBQueryImpl.executeReadQuery(EJBQueryImpl.java:485) at org.eclipse.persistence.internal.jpa.EJBQueryImpl.getResultList(EJBQueryImpl.java:742) at eclipsebug.BugMain.getItemByIdWithProps(BugMain.java:80) at eclipsebug.BugMain.doit(BugMain.java:56) at eclipsebug.BugMain.main(BugMain.java:15) A workaround is to set the query hint eclipselink.prepare=false. This does not fail in 2.2.x eclipselink lineage, fails in all 2.3.x versions I've tried up to and including 2.3.2 Reproducible: Always Steps to Reproduce: 1.Run included BugMain.java. Note it requires a persistence unit named EclipseLinkBug. I am running against SqlServer 2008 with unit: <persistence-unit name="EclipseLinkBug" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>eclipsebug.Prop</class> <class>eclipsebug.AllYourBase</class> <class>eclipsebug.SubThing</class> <exclude-unlisted-classes>true</exclude-unlisted-classes> <properties> <property name="javax.persistence.jdbc.url" value="jdbc:sqlserver:REMOVED"/> <property name="javax.persistence.jdbc.password" value="REMOVED"/> <property name="javax.persistence.jdbc.driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver"/> <property name="javax.persistence.jdbc.user" value="REMOVED"/> <property name="eclipselink.logging.level" value="FINE"/> <property name="eclipselink.canonicalmodel.subpackage" value="EclipseLinkBug"/> <property name="eclipselink.jdbc.batch-writing" value="JDBC"/> <property name="eclipselink.jdbc.cache-statements" value="false"/> <property name="eclipselink.jdbc.cache-statements.size" value="0"/> <property name="eclipselink.weaving" value="static"/> <property name="eclipselink.ddl-generation.output-mode" value="both"/> <property name="eclipselink.ddl-generation" value="create-tables"/> </properties> </persistence-unit> 2. 3.
Created attachment 210466 [details] code to reproduce defect 100% of the time see BugMain.java
Setting target and priority. See the following page for the meanings of these fields: http://wiki.eclipse.org/EclipseLink/Development/Bugs/Guidelines Community: Please vote for this bug if it is important to you. Votes are one of the main criteria we use to determine which bugs to fix next.
Created attachment 214642 [details] Suggested patch The problem arises because calls are shared by the cloned queries but JoinedAttributeManager are not. When the query executes it is cloned and the clone is actually executed. On the first execution of ExpressionQueryMechanism.selectAllRowsFromConcreteTable there is no call corresponding to the reference class, so new call is created and cached in query.getConcreteSubclassCalls(), which is shared between the clone and the original query; also buildConcreteSelectStatement, which sets into JoinedAttributeManager.computeJoiningMappingIndexes for the clone query (but NOT into the original). When the second cloned query executed ExpressionQueryMechanism.selectAllRowsFromConcreteTable has the cached call, so it no longer calls buildConcreteSelectStatement - but that means JoinedAttributeManager.computeJoiningMappingIndexes is left null -> NPE. The suggested solution is to follow with JoiningMappingIndexes the same pattern as with getConcreteSubclassCalls - keep them in a Map which is shared between all query's clones, keyed by query reference class. While implementing that I've noticed that getConcreteSubclassCalls is currently nullified on each query.setIsPrepared(false) - which happens on setting any new reference class unequal to the original one. Of course that completely defies the purpose of the whole arrangement: to keep the cached calls (and now joiningMappingIndexes, too) beyond setting of a new class. Therefore I've moved nullification of these two maps form query.setIsPrepared(false) to setIsPrePrepared(false). Test: EntityManagerJUnitTestSuite.testInheritanceFetchJoinSecondCall
Created attachment 214742 [details] Updated patch. Moved nullifying of concreteSubclass maps from setIsPrePrepared(false) back to setIsPrepared(false), define a new method setIsPreparedKeepingSubclassData to keep concreteSubclass maps when setting reference class and descriptor.
Created attachment 214810 [details] patch take 3 Following James's review: - set joined mapping indexes before setting call to avoid concurrency problem (the same NPE was still possible if call set before joined mapping indexes); - selectOneRowsromConcreteTable method follows the pattern of selectAllRowsFromConcreteTable method.
Checked the patch into both trunk (2.4) and 2.3.3. Reviewed by James.
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink