From 287a5167604a20f0e60f8f2862f91c746a12ca5b Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 29 Oct 2015 09:52:53 -0500 Subject: [PATCH] HHH-9230 - NullPointer when combining JPQL query with in clause and @NamedEntityGraph --- .../hibernate/internal/AbstractQueryImpl.java | 25 ++++- .../org/hibernate/jpa/internal/QueryImpl.java | 10 +- ...ithInParamListAndNamedEntityGraphTest.java | 95 +++++++++++++++++++ 3 files changed, 116 insertions(+), 14 deletions(-) create mode 100644 hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/query/QueryWithInParamListAndNamedEntityGraphTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractQueryImpl.java index 9c7300701d..034dde3eb2 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractQueryImpl.java @@ -33,6 +33,7 @@ import org.hibernate.Query; import org.hibernate.QueryException; import org.hibernate.Session; import org.hibernate.dialect.Dialect; +import org.hibernate.engine.query.spi.EntityGraphQueryHint; import org.hibernate.engine.query.spi.HQLQueryPlan; import org.hibernate.engine.query.spi.ParameterMetadata; import org.hibernate.engine.spi.QueryParameters; @@ -1026,11 +1027,25 @@ public abstract class AbstractQueryImpl implements Query { } } - public HQLQueryPlan getQueryPlan() { - return queryPlan; - } - public void setQueryPlan(HQLQueryPlan queryPlan) { - this.queryPlan = queryPlan; + /** + * Used from HEM code as a (hopefully temporary) means to apply a custom query plan + * in regards to a JPA entity graph. + * + * @param hint The entity graph hint object + */ + public void applyEntityGraphQueryHint(EntityGraphQueryHint hint) { + verifyParameters(); + // todo : likely need to update the instance state related to queryString and parameters + final Map namedParams = getNamedParams(); + final String expandedQuery = expandParameterLists( namedParams ); + this.queryPlan = new HQLQueryPlan( + expandedQuery, + false, + session.getLoadQueryInfluencers().getEnabledFilters(), + session.getFactory(), + hint + ); + } } diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/QueryImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/QueryImpl.java index e0c0ca71a3..67bf5a615a 100755 --- a/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/QueryImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/jpa/internal/QueryImpl.java @@ -553,16 +553,8 @@ public class QueryImpl extends AbstractQueryImpl private List list() { if ( getEntityGraphQueryHint() != null ) { - SessionImplementor sessionImpl = (SessionImplementor) getEntityManager().getSession(); - HQLQueryPlan entityGraphQueryPlan = new HQLQueryPlan( - getHibernateQuery().getQueryString(), - false, - sessionImpl.getLoadQueryInfluencers().getEnabledFilters(), - sessionImpl.getFactory(), - getEntityGraphQueryHint() - ); // Safe to assume QueryImpl at this point. - unwrap( org.hibernate.internal.QueryImpl.class ).setQueryPlan( entityGraphQueryPlan ); + unwrap( org.hibernate.internal.QueryImpl.class ).applyEntityGraphQueryHint( getEntityGraphQueryHint() ); } return query.list(); } diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/query/QueryWithInParamListAndNamedEntityGraphTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/query/QueryWithInParamListAndNamedEntityGraphTest.java new file mode 100644 index 0000000000..d7ef5d40a0 --- /dev/null +++ b/hibernate-entitymanager/src/test/java/org/hibernate/jpa/test/query/QueryWithInParamListAndNamedEntityGraphTest.java @@ -0,0 +1,95 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.jpa.test.query; + +import java.util.HashSet; +import java.util.Set; +import javax.persistence.Entity; +import javax.persistence.EntityManager; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.Table; +import javax.persistence.TypedQuery; + +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.hibernate.testing.TestForIssue; +import org.junit.Test; + +/** + * Based on the test developed by Hans Desmet to reproduce the bug reported in HHH-9230 + * + * @author Steve Ebersole + */ +@TestForIssue(jiraKey = "HHH-9230") +public class QueryWithInParamListAndNamedEntityGraphTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] {Person.class}; + } + + @Test + public void testInClause() { + // this test works + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Set ids = new HashSet(); + ids.add( 1L ); + ids.add( 2L ); + TypedQuery query = em.createQuery( "select p from Person p where p.id in :ids", Person.class ); + query.setParameter( "ids", ids ); + query.getResultList(); + em.getTransaction().commit(); + em.close(); + } + + @Test + public void testEntityGraph() { + // this test works + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + TypedQuery query = em.createQuery( "select p from Person p", Person.class ); + query.setHint( "javax.persistence.loadgraph", em.createEntityGraph( "withBoss" ) ); + query.getResultList(); + em.getTransaction().commit(); + em.close(); + } + + @Test + public void testEntityGraphAndInClause() { + // this test fails + EntityManager em = getOrCreateEntityManager(); + em.getTransaction().begin(); + Set ids = new HashSet(); + ids.add( 1L ); + ids.add( 2L ); + TypedQuery query = em.createQuery( "select p from Person p where p.id in :ids", Person.class ); + query.setHint( "javax.persistence.loadgraph", em.createEntityGraph( "withBoss" ) ); + query.setParameter( "ids", ids ); + query.getResultList(); + em.getTransaction().commit(); + em.close(); + } + + @Entity(name = "Person") + @Table(name = "Person") + @NamedEntityGraph(name = "withBoss", attributeNodes = @NamedAttributeNode("boss")) + public static class Person { + @Id + @GeneratedValue + private long id; + private String name; + @ManyToOne + @JoinColumn + private Person boss; + } +}