HHH-5348 - support for TypedQuery jpaql/hql "scalar" queries
This commit is contained in:
parent
7501fdea53
commit
d104f28a59
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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() {
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 <a href="mailto:gavin@hibernate.org">Gavin King</a>
|
||||
|
@ -279,18 +284,51 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
|
||||
public <T> TypedQuery<T> createQuery(String jpaqlString, Class<T> 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<T>( hqlQuery, this );
|
||||
}
|
||||
catch ( HibernateException he ) {
|
||||
|
@ -298,6 +336,139 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
}
|
||||
}
|
||||
|
||||
public static class TupleBuilderTransformer extends BasicTransformerAdapter {
|
||||
private List<TupleElement<?>> tupleElements;
|
||||
private Map<String,HqlTupleElementImpl> 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.<String, HqlTupleElementImpl>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<X> implements TupleElement<X> {
|
||||
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> X get(String alias, Class<X> 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> X get(int i, Class<X> 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<TupleElement<?>> getElements() {
|
||||
return tupleElements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> X get(TupleElement<X> tupleElement) {
|
||||
if ( HqlTupleElementImpl.class.isInstance( tupleElement ) ) {
|
||||
return get( ( (HqlTupleElementImpl) tupleElement ).getPosition(), tupleElement.getJavaType() );
|
||||
}
|
||||
else {
|
||||
return get( tupleElement.getAlias(), tupleElement.getJavaType() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public <T> TypedQuery<T> createQuery(
|
||||
String jpaqlString,
|
||||
Class<T> resultClass,
|
||||
|
|
|
@ -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[]{
|
||||
|
|
Loading…
Reference in New Issue