diff --git a/hibernate-core/src/main/java/org/hibernate/engine/query/HQLQueryPlan.java b/hibernate-core/src/main/java/org/hibernate/engine/query/HQLQueryPlan.java
index 4855673df6..a4e41bc5ef 100644
--- a/hibernate-core/src/main/java/org/hibernate/engine/query/HQLQueryPlan.java
+++ b/hibernate-core/src/main/java/org/hibernate/engine/query/HQLQueryPlan.java
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,7 +20,6 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.engine.query;
@@ -32,6 +31,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+
+import org.jboss.logging.Logger;
+
import org.hibernate.HibernateException;
import org.hibernate.HibernateLogger;
import org.hibernate.QueryException;
@@ -50,7 +52,6 @@ import org.hibernate.internal.util.collections.EmptyIterator;
import org.hibernate.internal.util.collections.IdentitySet;
import org.hibernate.internal.util.collections.JoinedIterator;
import org.hibernate.type.Type;
-import org.jboss.logging.Logger;
/**
* Defines a query execution plan for an HQL query (or filter).
@@ -331,4 +332,8 @@ public class HQLQueryPlan implements Serializable {
System.arraycopy(translators, 0, copy, 0, copy.length);
return copy;
}
+
+ public Class getDynamicInstantiationResultType() {
+ return translators[0].getDynamicInstantiationResultType();
+ }
}
diff --git a/hibernate-core/src/main/java/org/hibernate/hql/QueryTranslator.java b/hibernate-core/src/main/java/org/hibernate/hql/QueryTranslator.java
index b6dee910de..71ce4e4801 100644
--- a/hibernate-core/src/main/java/org/hibernate/hql/QueryTranslator.java
+++ b/hibernate-core/src/main/java/org/hibernate/hql/QueryTranslator.java
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,13 +20,14 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.hql;
+
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
@@ -185,4 +186,6 @@ public interface QueryTranslator {
boolean containsCollectionFetches();
boolean isManipulationStatement();
+
+ public Class getDynamicInstantiationResultType();
}
diff --git a/hibernate-core/src/main/java/org/hibernate/hql/ast/QueryTranslatorImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/ast/QueryTranslatorImpl.java
index 96b348fbdf..fbe4b527b2 100644
--- a/hibernate-core/src/main/java/org/hibernate/hql/ast/QueryTranslatorImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/hql/ast/QueryTranslatorImpl.java
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,7 +20,6 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.hql.ast;
@@ -30,6 +29,13 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
+
+import antlr.ANTLRException;
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+import antlr.collections.AST;
+import org.jboss.logging.Logger;
+
import org.hibernate.HibernateException;
import org.hibernate.HibernateLogger;
import org.hibernate.MappingException;
@@ -50,6 +56,7 @@ import org.hibernate.hql.ast.exec.BasicExecutor;
import org.hibernate.hql.ast.exec.MultiTableDeleteExecutor;
import org.hibernate.hql.ast.exec.MultiTableUpdateExecutor;
import org.hibernate.hql.ast.exec.StatementExecutor;
+import org.hibernate.hql.ast.tree.AggregatedSelectExpression;
import org.hibernate.hql.ast.tree.FromElement;
import org.hibernate.hql.ast.tree.InsertStatement;
import org.hibernate.hql.ast.tree.QueryNode;
@@ -63,11 +70,6 @@ import org.hibernate.internal.util.collections.IdentitySet;
import org.hibernate.loader.hql.QueryLoader;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.type.Type;
-import org.jboss.logging.Logger;
-import antlr.ANTLRException;
-import antlr.RecognitionException;
-import antlr.TokenStreamException;
-import antlr.collections.AST;
/**
* A QueryTranslator that uses an Antlr-based parser.
@@ -564,6 +566,12 @@ public class QueryTranslatorImpl implements FilterTranslator {
return collectedParameterSpecifications;
}
+ @Override
+ public Class getDynamicInstantiationResultType() {
+ AggregatedSelectExpression aggregation = queryLoader.getAggregatedSelectExpression();
+ return aggregation == null ? null : aggregation.getAggregationResultType();
+ }
+
public static class JavaConstantConverter implements NodeTraverser.VisitationStrategy {
private AST dotRoot;
public void visit(AST node) {
diff --git a/hibernate-core/src/main/java/org/hibernate/hql/ast/tree/AggregatedSelectExpression.java b/hibernate-core/src/main/java/org/hibernate/hql/ast/tree/AggregatedSelectExpression.java
index 1556d938de..c43ca11474 100644
--- a/hibernate-core/src/main/java/org/hibernate/hql/ast/tree/AggregatedSelectExpression.java
+++ b/hibernate-core/src/main/java/org/hibernate/hql/ast/tree/AggregatedSelectExpression.java
@@ -1,8 +1,10 @@
/*
- * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,7 +22,9 @@
* Boston, MA 02110-1301 USA
*/
package org.hibernate.hql.ast.tree;
+
import java.util.List;
+
import org.hibernate.transform.ResultTransformer;
/**
@@ -50,4 +54,11 @@ public interface AggregatedSelectExpression extends SelectExpression {
* @return The appropriate transformer
*/
public ResultTransformer getResultTransformer();
+
+ /**
+ * Obtain the java type of the aggregation
+ *
+ * @return The java type.
+ */
+ public Class getAggregationResultType();
}
diff --git a/hibernate-core/src/main/java/org/hibernate/hql/ast/tree/ConstructorNode.java b/hibernate-core/src/main/java/org/hibernate/hql/ast/tree/ConstructorNode.java
index 7232a3deea..c8f5f302ec 100644
--- a/hibernate-core/src/main/java/org/hibernate/hql/ast/tree/ConstructorNode.java
+++ b/hibernate-core/src/main/java/org/hibernate/hql/ast/tree/ConstructorNode.java
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,13 +20,17 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.hql.ast.tree;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
+
+import antlr.SemanticException;
+import antlr.collections.AST;
+
import org.hibernate.PropertyNotFoundException;
import org.hibernate.QueryException;
import org.hibernate.hql.ast.DetailedSemanticException;
@@ -36,8 +40,6 @@ import org.hibernate.transform.AliasToBeanConstructorResultTransformer;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.transform.Transformers;
import org.hibernate.type.Type;
-import antlr.SemanticException;
-import antlr.collections.AST;
/**
* Represents a constructor (new) in a SELECT.
@@ -45,11 +47,11 @@ import antlr.collections.AST;
* @author josh
*/
public class ConstructorNode extends SelectExpressionList implements AggregatedSelectExpression {
+ private Class resultType;
private Constructor constructor;
private Type[] constructorArgumentTypes;
private boolean isMap;
private boolean isList;
- private int scalarColumnIndex = -1;
public ResultTransformer getResultTransformer() {
if ( constructor != null ) {
@@ -64,14 +66,6 @@ public class ConstructorNode extends SelectExpressionList implements AggregatedS
throw new QueryException( "Unable to determine proper dynamic-instantiation tranformer to use." );
}
- public boolean isMap() {
- return isMap;
- }
-
- public boolean isList() {
- return isList;
- }
-
private String[] aggregatedAliases;
public String[] getAggregatedAliases() {
@@ -101,7 +95,7 @@ public class ConstructorNode extends SelectExpressionList implements AggregatedS
}
public int getScalarColumnIndex() {
- return scalarColumnIndex;
+ return -1;
}
public void setScalarColumnText(int i) throws SemanticException {
@@ -119,6 +113,11 @@ public class ConstructorNode extends SelectExpressionList implements AggregatedS
return getFirstChild().getNextSibling();
}
+ @Override
+ public Class getAggregationResultType() {
+ return resultType;
+ }
+
/**
* @deprecated (tell clover to ignore this method)
*/
@@ -143,12 +142,15 @@ public class ConstructorNode extends SelectExpressionList implements AggregatedS
String path = ( ( PathNode ) getFirstChild() ).getPath();
if ( "map".equals( path.toLowerCase() ) ) {
isMap = true;
+ resultType = Map.class;
}
else if ( "list".equals( path.toLowerCase() ) ) {
isList = true;
+ resultType = List.class;
}
else {
- constructor = resolveConstructor(path);
+ constructor = resolveConstructor( path );
+ resultType = constructor.getDeclaringClass();
}
}
diff --git a/hibernate-core/src/main/java/org/hibernate/hql/ast/tree/MapEntryNode.java b/hibernate-core/src/main/java/org/hibernate/hql/ast/tree/MapEntryNode.java
index e1485a03f4..6ebe7f84be 100644
--- a/hibernate-core/src/main/java/org/hibernate/hql/ast/tree/MapEntryNode.java
+++ b/hibernate-core/src/main/java/org/hibernate/hql/ast/tree/MapEntryNode.java
@@ -63,6 +63,11 @@ public class MapEntryNode extends AbstractMapComponentNode implements Aggregated
return "entry(*)";
}
+ @Override
+ public Class getAggregationResultType() {
+ return Map.Entry.class;
+ }
+
protected Type resolveType(QueryableCollection collectionPersister) {
Type keyType = collectionPersister.getIndexType();
Type valueType = collectionPersister.getElementType();
diff --git a/hibernate-core/src/main/java/org/hibernate/hql/classic/QueryTranslatorImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/classic/QueryTranslatorImpl.java
index 0a16636291..acb54eca99 100644
--- a/hibernate-core/src/main/java/org/hibernate/hql/classic/QueryTranslatorImpl.java
+++ b/hibernate-core/src/main/java/org/hibernate/hql/classic/QueryTranslatorImpl.java
@@ -1193,6 +1193,11 @@ public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator
return false;
}
+ @Override
+ public Class getDynamicInstantiationResultType() {
+ return holderClass;
+ }
+
public ParameterTranslations getParameterTranslations() {
return new ParameterTranslations() {
diff --git a/hibernate-core/src/main/java/org/hibernate/loader/hql/QueryLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/hql/QueryLoader.java
index cacfe4bd9c..e8294c16b5 100644
--- a/hibernate-core/src/main/java/org/hibernate/loader/hql/QueryLoader.java
+++ b/hibernate-core/src/main/java/org/hibernate/loader/hql/QueryLoader.java
@@ -1,10 +1,10 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
- * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
+ * Copyright (c) 2008-2011, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
- * distributed under license by Red Hat Middleware LLC.
+ * distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
@@ -20,9 +20,9 @@
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
- *
*/
package org.hibernate.loader.hql;
+
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -31,6 +31,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
@@ -96,7 +97,7 @@ public class QueryLoader extends BasicLoader {
private int selectLength;
- private ResultTransformer implicitResultTransformer;
+ private AggregatedSelectExpression aggregatedSelectExpression;
private String[] queryReturnAliases;
private LockMode[] defaultLockModes;
@@ -128,10 +129,7 @@ public class QueryLoader extends BasicLoader {
//sqlResultTypes = selectClause.getSqlResultTypes();
queryReturnTypes = selectClause.getQueryReturnTypes();
- AggregatedSelectExpression aggregatedSelectExpression = selectClause.getAggregatedSelectExpression();
- implicitResultTransformer = aggregatedSelectExpression == null
- ? null
- : aggregatedSelectExpression.getResultTransformer();
+ aggregatedSelectExpression = selectClause.getAggregatedSelectExpression();
queryReturnAliases = selectClause.getQueryReturnAliases();
List collectionFromElements = selectClause.getCollectionFromElements();
@@ -199,6 +197,11 @@ public class QueryLoader extends BasicLoader {
defaultLockModes = ArrayHelper.fillArray( LockMode.NONE, size );
}
+ public AggregatedSelectExpression getAggregatedSelectExpression() {
+ return aggregatedSelectExpression;
+ }
+
+
// -- Loader implementation --
public final void validateScrollability() throws HibernateException {
@@ -375,7 +378,7 @@ public class QueryLoader extends BasicLoader {
}
private boolean hasSelectNew() {
- return implicitResultTransformer != null;
+ return aggregatedSelectExpression != null && aggregatedSelectExpression.getResultTransformer() != null;
}
protected String[] getResultRowAliases() {
@@ -383,6 +386,9 @@ public class QueryLoader extends BasicLoader {
}
protected ResultTransformer resolveResultTransformer(ResultTransformer resultTransformer) {
+ final ResultTransformer implicitResultTransformer = aggregatedSelectExpression == null
+ ? null
+ : aggregatedSelectExpression.getResultTransformer();
return HolderInstantiator.resolveResultTransformer( implicitResultTransformer, resultTransformer );
}
@@ -446,6 +452,9 @@ public class QueryLoader extends BasicLoader {
}
private HolderInstantiator buildHolderInstantiator(ResultTransformer queryLocalResultTransformer) {
+ final ResultTransformer implicitResultTransformer = aggregatedSelectExpression == null
+ ? null
+ : aggregatedSelectExpression.getResultTransformer();
return HolderInstantiator.getHolderInstantiator(
implicitResultTransformer,
queryLocalResultTransformer,
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 98f5a1b5b1..71a0201046 100755
--- a/hibernate-entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
+++ b/hibernate-entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
@@ -23,15 +23,6 @@
*/
package org.hibernate.ejb;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
import javax.persistence.CacheRetrieveMode;
import javax.persistence.CacheStoreMode;
import javax.persistence.EntityManager;
@@ -60,6 +51,18 @@ import javax.persistence.metamodel.Metamodel;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.jboss.logging.Logger;
+
import org.hibernate.AssertionFailure;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
@@ -88,6 +91,7 @@ import org.hibernate.engine.NamedSQLQueryDefinition;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.query.HQLQueryPlan;
import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
@@ -99,10 +103,11 @@ import org.hibernate.engine.transaction.synchronization.spi.ExceptionMapper;
import org.hibernate.engine.transaction.synchronization.spi.ManagedFlushChecker;
import org.hibernate.engine.transaction.synchronization.spi.SynchronizationCallbackCoordinator;
import org.hibernate.internal.util.ReflectHelper;
+import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.hibernate.transform.BasicTransformerAdapter;
-import org.jboss.logging.Logger;
+import org.hibernate.type.Type;
/**
* @author Gavin King
@@ -279,18 +284,51 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
public TypedQuery createQuery(String jpaqlString, Class resultClass) {
try {
+ // do the translation
org.hibernate.Query hqlQuery = getSession().createQuery( jpaqlString );
- if ( hqlQuery.getReturnTypes().length != 1 ) {
- throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" );
+
+ // do some validation checking
+ if ( Object[].class.equals( resultClass ) ) {
+ // no validation needed
}
- 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 if ( Tuple.class.equals( resultClass ) ) {
+ TupleBuilderTransformer tupleTransformer = new TupleBuilderTransformer( hqlQuery );
+ hqlQuery.setResultTransformer( tupleTransformer );
}
+ else {
+ final HQLQueryPlan queryPlan = unwrap( SessionImplementor.class )
+ .getFactory()
+ .getQueryPlanCache()
+ .getHQLQueryPlan( jpaqlString, false, null );
+ 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() + "]"
+ );
+ }
+ }
+
+ // finally, build/return the query instance
return new QueryImpl( hqlQuery, this );
}
catch ( HibernateException he ) {
@@ -298,6 +336,139 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
}
}
+ public static class TupleBuilderTransformer extends BasicTransformerAdapter {
+ private List> tupleElements;
+ private Map tupleElementsByAlias;
+
+ public TupleBuilderTransformer(org.hibernate.Query hqlQuery) {
+ final Type[] resultTypes = hqlQuery.getReturnTypes();
+ final int tupleSize = resultTypes.length;
+
+ this.tupleElements = CollectionHelper.arrayList( tupleSize );
+
+ final String[] aliases = hqlQuery.getReturnAliases();
+ final boolean hasAliases = aliases != null && aliases.length > 0;
+ this.tupleElementsByAlias = hasAliases
+ ? CollectionHelper.mapOfSize( tupleSize )
+ : Collections.emptyMap();
+
+ for ( int i = 0; i < tupleSize; i++ ) {
+ final HqlTupleElementImpl tupleElement = new HqlTupleElementImpl(
+ i,
+ aliases == null ? null : aliases[i],
+ resultTypes[i]
+ );
+ tupleElements.add( tupleElement );
+ if ( hasAliases ) {
+ final String alias = aliases[i];
+ if ( alias != null ) {
+ tupleElementsByAlias.put( alias, tupleElement );
+ }
+ }
+ }
+ }
+
+ @Override
+ public Object transformTuple(Object[] tuple, String[] aliases) {
+ if ( tuple.length != tupleElements.size() ) {
+ throw new IllegalArgumentException(
+ "Size mismatch between tuple result [" + tuple.length + "] and expected tuple elements [" +
+ tupleElements.size() + "]"
+ );
+ }
+ return new HqlTupleImpl( tuple );
+ }
+
+ public static class HqlTupleElementImpl implements TupleElement {
+ private final int position;
+ private final String alias;
+ private final Type hibernateType;
+
+ public HqlTupleElementImpl(int position, String alias, Type hibernateType) {
+ this.position = position;
+ this.alias = alias;
+ this.hibernateType = hibernateType;
+ }
+
+ @Override
+ public Class getJavaType() {
+ return hibernateType.getReturnedClass();
+ }
+
+ @Override
+ public String getAlias() {
+ return alias;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+
+ public Type getHibernateType() {
+ return hibernateType;
+ }
+ }
+
+ public class HqlTupleImpl implements Tuple {
+ private Object[] tuple;
+
+ public HqlTupleImpl(Object[] tuple) {
+ this.tuple = tuple;
+ }
+
+ @Override
+ public X get(String alias, Class type) {
+ return (X) get( alias );
+ }
+
+ @Override
+ public Object get(String alias) {
+ HqlTupleElementImpl tupleElement = tupleElementsByAlias.get( alias );
+ if ( tupleElement == null ) {
+ throw new IllegalArgumentException( "Unknown alias [" + alias + "]" );
+ }
+ return tuple[ tupleElement.getPosition() ];
+ }
+
+ @Override
+ public X get(int i, Class type) {
+ return (X) get( i );
+ }
+
+ @Override
+ public Object get(int i) {
+ if ( i < 0 ) {
+ throw new IllegalArgumentException( "requested tuple index must be greater than zero" );
+ }
+ if ( i > tuple.length ) {
+ throw new IllegalArgumentException( "requested tuple index exceeds actual tuple size" );
+ }
+ return tuple[i];
+ }
+
+ @Override
+ public Object[] toArray() {
+ // todo : make a copy?
+ return tuple;
+ }
+
+ @Override
+ public List> getElements() {
+ return tupleElements;
+ }
+
+ @Override
+ public X get(TupleElement tupleElement) {
+ if ( HqlTupleElementImpl.class.isInstance( tupleElement ) ) {
+ return get( ( (HqlTupleElementImpl) tupleElement ).getPosition(), tupleElement.getJavaType() );
+ }
+ else {
+ return get( tupleElement.getAlias(), tupleElement.getJavaType() );
+ }
+ }
+ }
+ }
+
public TypedQuery createQuery(
String jpaqlString,
Class resultClass,
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 3d17820564..36b0fd00be 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
@@ -26,6 +26,7 @@ package org.hibernate.ejb.test.query;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TemporalType;
+import javax.persistence.Tuple;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -522,6 +523,33 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
em.close();
}
+ @Test
+ public void testTypedScalarQueries() {
+ EntityManager em = getOrCreateEntityManager();
+ em.getTransaction().begin();
+ Item item = new Item( "Mouse", "Micro$oft mouse" );
+ em.persist( item );
+ assertTrue( em.contains( item ) );
+ em.getTransaction().commit();
+
+ em.getTransaction().begin();
+ Object[] itemData = em.createQuery( "select i.name,i.descr from Item i", Object[].class ).getSingleResult();
+ assertEquals( 2, itemData.length );
+ assertEquals( String.class, itemData[0].getClass() );
+ assertEquals( String.class, itemData[1].getClass() );
+ Tuple itemTuple = em.createQuery( "select i.name,i.descr from Item i", Tuple.class ).getSingleResult();
+ assertEquals( 2, itemTuple.getElements().size() );
+ assertEquals( String.class, itemTuple.get( 0 ).getClass() );
+ assertEquals( String.class, itemTuple.get( 1 ).getClass() );
+ 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() );
+ em.remove( item );
+ em.getTransaction().commit();
+
+ em.close();
+ }
+
@Override
public Class[] getAnnotatedClasses() {
return new Class[]{