HHH-6304 HHH-6695 Error 'Cannot create TypedQuery for query with more than one return' with named queries

This commit is contained in:
Strong Liu 2012-07-12 11:53:27 +08:00
parent c46daa4cf0
commit 973451d5e8
3 changed files with 59 additions and 54 deletions

View File

@ -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<T>( 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<T>( namedQuery, this );
}
@ -716,6 +666,56 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
}
}
private <T> void resultClassChecking(Class<T> 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 [" +

View File

@ -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 {

View File

@ -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();