From 973451d5e8985d03244f3a4ac8c674ca49a1fabb Mon Sep 17 00:00:00 2001 From: Strong Liu Date: Thu, 12 Jul 2012 11:53:27 +0800 Subject: [PATCH] HHH-6304 HHH-6695 Error 'Cannot create TypedQuery for query with more than one return' with named queries --- .../ejb/AbstractEntityManagerImpl.java | 108 +++++++++--------- .../java/org/hibernate/ejb/test/Item.java | 2 + .../hibernate/ejb/test/query/QueryTest.java | 3 + 3 files changed, 59 insertions(+), 54 deletions(-) diff --git a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java index 5cdfe17f0d..216d002cbe 100755 --- a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java +++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java @@ -300,53 +300,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage // do the translation org.hibernate.Query hqlQuery = getSession().createQuery( jpaqlString ); - // make sure the query is a select -> HHH-7192 - final SessionImplementor session = unwrap( SessionImplementor.class ); - final HQLQueryPlan queryPlan = session.getFactory().getQueryPlanCache().getHQLQueryPlan( - jpaqlString, - false, - session.getLoadQueryInfluencers().getEnabledFilters() - ); - if ( queryPlan.getTranslators()[0].isManipulationStatement() ) { - throw new IllegalArgumentException( "Update/delete queries cannot be typed" ); - } - - // do some return type validation checking - if ( Object[].class.equals( resultClass ) ) { - // no validation needed - } - else if ( Tuple.class.equals( resultClass ) ) { - TupleBuilderTransformer tupleTransformer = new TupleBuilderTransformer( hqlQuery ); - hqlQuery.setResultTransformer( tupleTransformer ); - } - else { - final Class dynamicInstantiationClass = queryPlan.getDynamicInstantiationResultType(); - if ( dynamicInstantiationClass != null ) { - if ( ! resultClass.isAssignableFrom( dynamicInstantiationClass ) ) { - throw new IllegalArgumentException( - "Mismatch in requested result type [" + resultClass.getName() + - "] and actual result type [" + dynamicInstantiationClass.getName() + "]" - ); - } - } - else if ( hqlQuery.getReturnTypes().length == 1 ) { - // if we have only a single return expression, its java type should match with the requested type - if ( !resultClass.isAssignableFrom( hqlQuery.getReturnTypes()[0].getReturnedClass() ) ) { - throw new IllegalArgumentException( - "Type specified for TypedQuery [" + - resultClass.getName() + - "] is incompatible with query return type [" + - hqlQuery.getReturnTypes()[0].getReturnedClass() + "]" - ); - } - } - else { - throw new IllegalArgumentException( - "Cannot create TypedQuery for query with more than one return using requested result type [" + - resultClass.getName() + "]" - ); - } - } + resultClassChecking( resultClass, hqlQuery ); // finally, build/return the query instance return new QueryImpl( hqlQuery, this ); @@ -658,7 +612,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage */ org.hibernate.Query namedQuery = getSession().getNamedQuery( name ); //TODO clean this up to avoid downcasting - final SessionFactoryImplementor factoryImplementor = ( SessionFactoryImplementor ) entityManagerFactory.getSessionFactory(); + final SessionFactoryImplementor factoryImplementor = entityManagerFactory.getSessionFactory(); final NamedSQLQueryDefinition queryDefinition = factoryImplementor.getNamedSQLQuery( name ); try { if ( queryDefinition != null ) { @@ -698,12 +652,8 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage } } else { - if ( namedQuery.getReturnTypes().length != 1 ) { - throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" ); - } - if ( !resultClass.isAssignableFrom( namedQuery.getReturnTypes()[0].getReturnedClass() ) ) { - throw buildIncompatibleException( resultClass, namedQuery.getReturnTypes()[0].getReturnedClass() ); - } + resultClassChecking( resultClass, namedQuery ); + } return new QueryImpl( namedQuery, this ); } @@ -716,6 +666,56 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage } } + private void resultClassChecking(Class resultClass, org.hibernate.Query query) { + // make sure the query is a select -> HHH-7192 + final SessionImplementor session = unwrap( SessionImplementor.class ); + final HQLQueryPlan queryPlan = session.getFactory().getQueryPlanCache().getHQLQueryPlan( + query.getQueryString(), + false, + session.getLoadQueryInfluencers().getEnabledFilters() + ); + if ( queryPlan.getTranslators()[0].isManipulationStatement() ) { + throw new IllegalArgumentException( "Update/delete queries cannot be typed" ); + } + + // do some return type validation checking + if ( Object[].class.equals( resultClass ) ) { + // no validation needed + } + else if ( Tuple.class.equals( resultClass ) ) { + TupleBuilderTransformer tupleTransformer = new TupleBuilderTransformer( query ); + query.setResultTransformer( tupleTransformer ); + } + else { + final Class dynamicInstantiationClass = queryPlan.getDynamicInstantiationResultType(); + if ( dynamicInstantiationClass != null ) { + if ( ! resultClass.isAssignableFrom( dynamicInstantiationClass ) ) { + throw new IllegalArgumentException( + "Mismatch in requested result type [" + resultClass.getName() + + "] and actual result type [" + dynamicInstantiationClass.getName() + "]" + ); + } + } + else if ( query.getReturnTypes().length == 1 ) { + // if we have only a single return expression, its java type should match with the requested type + if ( !resultClass.isAssignableFrom( query.getReturnTypes()[0].getReturnedClass() ) ) { + throw new IllegalArgumentException( + "Type specified for TypedQuery [" + + resultClass.getName() + + "] is incompatible with query return type [" + + query.getReturnTypes()[0].getReturnedClass() + "]" + ); + } + } + else { + throw new IllegalArgumentException( + "Cannot create TypedQuery for query with more than one return using requested result type [" + + resultClass.getName() + "]" + ); + } + } + } + private IllegalArgumentException buildIncompatibleException(Class resultClass, Class actualResultClass) { return new IllegalArgumentException( "Type specified for TypedQuery [" + diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/ejb/test/Item.java b/hibernate-entitymanager/src/test/java/org/hibernate/ejb/test/Item.java index 11446ef0d0..01ad2162ae 100755 --- a/hibernate-entitymanager/src/test/java/org/hibernate/ejb/test/Item.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/ejb/test/Item.java @@ -10,6 +10,7 @@ import javax.persistence.FieldResult; import javax.persistence.Id; import javax.persistence.NamedNativeQueries; import javax.persistence.NamedNativeQuery; +import javax.persistence.NamedQuery; import javax.persistence.OneToMany; import javax.persistence.SqlResultSetMapping; @@ -35,6 +36,7 @@ import javax.persistence.SqlResultSetMapping; resultClass = Item.class ) }) +@NamedQuery(name = "query-construct", query = "select new Item(i.name,i.descr) from Item i") //@Cache(region="Item", usage=NONSTRICT_READ_WRITE) public class Item implements Serializable { diff --git a/hibernate-entitymanager/src/test/java/org/hibernate/ejb/test/query/QueryTest.java b/hibernate-entitymanager/src/test/java/org/hibernate/ejb/test/query/QueryTest.java index 4057a8202a..2c0502fea8 100644 --- a/hibernate-entitymanager/src/test/java/org/hibernate/ejb/test/query/QueryTest.java +++ b/hibernate-entitymanager/src/test/java/org/hibernate/ejb/test/query/QueryTest.java @@ -583,6 +583,9 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase { Item itemView = em.createQuery( "select new Item(i.name,i.descr) from Item i", Item.class ).getSingleResult(); assertNotNull( itemView ); assertEquals( "Micro$oft mouse", itemView.getDescr() ); + itemView = em.createNamedQuery( "query-construct", Item.class ).getSingleResult(); + assertNotNull( itemView ); + assertEquals( "Micro$oft mouse", itemView.getDescr() ); em.remove( item ); em.getTransaction().commit();