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[]{