[hibernate-commits] Hibernate SVN: r18444 - in core/trunk/entitymanager/src: main/java/org/hibernate/ejb/criteria and 2 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Thu Jan 7 15:41:55 EST 2010


Author: steve.ebersole at jboss.com
Date: 2010-01-07 15:41:54 -0500 (Thu, 07 Jan 2010)
New Revision: 18444

Removed:
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/criteria/tuple/Customer.java
Modified:
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/HibernateEntityManagerImplementor.java
   core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaQueryCompiler.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/criteria/tuple/TupleCriteriaTest.java
   core/trunk/entitymanager/src/test/java/org/hibernate/ejb/metamodel/Customer.java
Log:
HHH-4724 - query.multiselect() on a CriteriaQuery<Tuple> returns List<Object[]> instead of List<Tuple>


Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java	2010-01-07 20:34:59 UTC (rev 18443)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/AbstractEntityManagerImpl.java	2010-01-07 20:41:54 UTC (rev 18444)
@@ -41,12 +41,15 @@
 import javax.persistence.PessimisticLockException;
 import javax.persistence.Query;
 import javax.persistence.TransactionRequiredException;
+import javax.persistence.Tuple;
+import javax.persistence.TupleElement;
 import javax.persistence.TypedQuery;
 import javax.persistence.PessimisticLockScope;
 import javax.persistence.LockTimeoutException;
 import javax.persistence.QueryTimeoutException;
 import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.Selection;
 import javax.persistence.metamodel.Metamodel;
 import javax.persistence.spi.PersistenceUnitTransactionType;
 import javax.transaction.Status;
@@ -60,6 +63,7 @@
 import org.hibernate.*;
 import org.hibernate.cfg.Environment;
 import org.hibernate.ejb.criteria.ValueHandlerFactory;
+import org.hibernate.ejb.criteria.expression.CompoundSelectionImpl;
 import org.hibernate.ejb.transaction.JoinableCMTTransaction;
 import org.hibernate.ejb.util.ConfigurationHelper;
 import org.hibernate.ejb.criteria.CriteriaQueryCompiler;
@@ -68,6 +72,7 @@
 import org.hibernate.proxy.HibernateProxy;
 import org.hibernate.transaction.TransactionFactory;
 import org.hibernate.transform.BasicTransformerAdapter;
+import org.hibernate.transform.ResultTransformer;
 import org.hibernate.util.CollectionHelper;
 import org.hibernate.util.JTAHelper;
 
@@ -145,15 +150,24 @@
 	public <T> TypedQuery<T> createQuery(
 			String jpaqlString,
 			Class<T> resultClass,
+			Selection selection,
 			Options options) {
 		try {
 			org.hibernate.Query hqlQuery = getSession().createQuery( jpaqlString );
-			if ( options.getValueHandlers() != null ) {
-				hqlQuery.setResultTransformer( new ValueConversionResultTransformer(  options.getValueHandlers() ) );
-			}
-			else {
+
+			if ( options.getValueHandlers() == null ) {
 				options.getResultMetadataValidator().validate( hqlQuery.getReturnTypes() );
 			}
+
+			// determine if we need a result transformer
+			List tupleElements = Tuple.class.equals( resultClass )
+					? ( (CompoundSelectionImpl<Tuple>) selection ).getCompoundSelectionItems()
+					: null;
+			if ( options.getValueHandlers() != null || tupleElements != null ) {
+				hqlQuery.setResultTransformer(
+						new CriteriaQueryTransformer( options.getValueHandlers(), tupleElements )
+				);
+			}
 			return new QueryImpl<T>( hqlQuery, this, options.getNamedParameterExplicitTypes() );
 		}
 		catch ( HibernateException he ) {
@@ -161,24 +175,109 @@
 		}
 	}
 
-	private static class ValueConversionResultTransformer extends BasicTransformerAdapter {
-		private List<ValueHandlerFactory.ValueHandler> valueHandlers;
+	private static class CriteriaQueryTransformer extends BasicTransformerAdapter {
+		private final List<ValueHandlerFactory.ValueHandler> valueHandlers;
+		private final List tupleElements;
 
-		private ValueConversionResultTransformer(List<ValueHandlerFactory.ValueHandler> valueHandlers) {
+		private CriteriaQueryTransformer(List<ValueHandlerFactory.ValueHandler> valueHandlers, List tupleElements) {
+			// todo : should these 2 sizes match *always*?
 			this.valueHandlers = valueHandlers;
+			this.tupleElements = tupleElements;
 		}
 
 		@Override
 		public Object transformTuple(Object[] tuple, String[] aliases) {
-			Object[] result = new Object[ tuple.length ];
-			for ( int i = 0; i < tuple.length; i++ ) {
-				ValueHandlerFactory.ValueHandler valueHandler = valueHandlers.get( i );
-				result[i] = valueHandler == null
-						? tuple[i]
-						: valueHandler.convert( tuple[i] );
+			final Object[] valueHandlerResult;
+			if ( valueHandlers == null ) {
+				valueHandlerResult = tuple;
 			}
-			return result.length == 1 ? result[0] : result;
+			else {
+				valueHandlerResult = new Object[ tuple.length ];
+				for ( int i = 0; i < tuple.length; i++ ) {
+					ValueHandlerFactory.ValueHandler valueHandler = valueHandlers.get( i );
+					valueHandlerResult[i] = valueHandler == null
+							? tuple[i]
+							: valueHandler.convert( tuple[i] );
+				}
+			}
+
+			return tupleElements == null
+					? valueHandlerResult.length == 1 ? valueHandlerResult[0] : valueHandlerResult
+					: new TupleImpl( tuple );
+
 		}
+
+		private class TupleImpl implements Tuple {
+			private final Object[] tuples;
+
+			private TupleImpl(Object[] tuples) {
+				if ( tuples.length != tupleElements.size() ) {
+					throw new IllegalArgumentException(
+							"Size mismatch between tuple result [" + tuples.length
+									+ "] and expected tuple elements [" + tupleElements.size() + "]"
+					);
+				}
+				this.tuples = tuples;
+			}
+
+			public <X> X get(TupleElement<X> tupleElement) {
+				int index = tupleElements.indexOf( tupleElement );
+				if ( index < 0 ) {
+					throw new IllegalArgumentException( "Requested tuple element did not correspond to element in the result tuple" );
+				}
+				// index should be "in range" by nature of size check in ctor
+				return (X) tuples[index];
+			}
+
+			public Object get(String alias) {
+				int index = -1;
+				if ( alias != null ) {
+					alias = alias.trim();
+					if ( alias.length() > 0 ) {
+						int i = 0;
+						for ( TupleElement selection : (List<TupleElement>) tupleElements ) {
+							if ( alias.equals( selection.getAlias() ) ) {
+								index = i;
+								break;
+							}
+							i++;
+						}
+					}
+				}
+				if ( index < 0 ) {
+					throw new IllegalArgumentException(
+							"Given alias [" + alias + "] did not correspond to an element in the result tuple"
+					);
+				}
+				// index should be "in range" by nature of size check in ctor
+				return tuples[index];
+			}
+
+			public <X> X get(String alias, Class<X> type) {
+				return (X) get( alias );
+			}
+
+			public Object get(int i) {
+				if ( i >= tuples.length ) {
+					throw new IllegalArgumentException(
+							"Given index [" + i + "] was outside the range of result tuple size [" + tuples.length + "] "
+					);
+				}
+				return tuples[i];
+			}
+
+			public <X> X get(int i, Class<X> type) {
+				return (X) get( i );
+			}
+
+			public Object[] toArray() {
+				return tuples;
+			}
+
+			public List<TupleElement<?>> getElements() {
+				return (List<TupleElement<?>>) tupleElements;
+			}
+		}
 	}
 
 	private CriteriaQueryCompiler criteriaQueryCompiler;

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/HibernateEntityManagerImplementor.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/HibernateEntityManagerImplementor.java	2010-01-07 20:34:59 UTC (rev 18443)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/HibernateEntityManagerImplementor.java	2010-01-07 20:41:54 UTC (rev 18444)
@@ -26,6 +26,7 @@
 import javax.persistence.PersistenceException;
 import javax.persistence.LockModeType;
 import javax.persistence.TypedQuery;
+import javax.persistence.criteria.Selection;
 
 import org.hibernate.HibernateException;
 import org.hibernate.StaleStateException;
@@ -141,9 +142,10 @@
 	 *
 	 * @param jpaqlString The criteria query rendered as a JPA QL string
 	 * @param resultClass The result type (the type expected in the result list)
+	 * @param selection The selection(s)
 	 * @param options The options to use to build the query.
 	 * @param <T> The query type
 	 * @return The typed query
 	 */
-	public <T> TypedQuery<T> createQuery(String jpaqlString, Class<T> resultClass, Options options);
+	public <T> TypedQuery<T> createQuery(String jpaqlString, Class<T> resultClass, Selection selection, Options options);
 }

Modified: core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaQueryCompiler.java
===================================================================
--- core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaQueryCompiler.java	2010-01-07 20:34:59 UTC (rev 18443)
+++ core/trunk/entitymanager/src/main/java/org/hibernate/ejb/criteria/CriteriaQueryCompiler.java	2010-01-07 20:41:54 UTC (rev 18444)
@@ -154,6 +154,7 @@
 		TypedQuery<T> jpaqlQuery = entityManager.createQuery(
 				renderedCriteriaQuery.getQueryString(),
 				criteriaQuery.getResultType(),
+				criteriaQuery.getSelection(),
 				new HibernateEntityManagerImplementor.Options() {
 					public List<ValueHandlerFactory.ValueHandler> getValueHandlers() {
 						return renderedCriteriaQuery.getValueHandlers();

Deleted: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/criteria/tuple/Customer.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/criteria/tuple/Customer.java	2010-01-07 20:34:59 UTC (rev 18443)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/criteria/tuple/Customer.java	2010-01-07 20:41:54 UTC (rev 18444)
@@ -1,43 +0,0 @@
-package org.hibernate.ejb.criteria.tuple;
-
-import javax.persistence.Table;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.GeneratedValue;
-
-/**
- * @author Emmanuel Bernard
- */
- at Entity
- at Table(name="tup_cust")
-public class Customer {
-	private Long id;
-	private String name;
-	private Integer age;
-
-	@Id
-	@GeneratedValue
-	public Long getId() {
-		return id;
-	}
-
-	public void setId(Long id) {
-		this.id = id;
-	}
-
-	public String getName() {
-		return name;
-	}
-
-	public void setName(String name) {
-		this.name = name;
-	}
-
-	public Integer getAge() {
-		return age;
-	}
-
-	public void setAge(Integer age) {
-		this.age = age;
-	}
-}

Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/criteria/tuple/TupleCriteriaTest.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/criteria/tuple/TupleCriteriaTest.java	2010-01-07 20:34:59 UTC (rev 18443)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/criteria/tuple/TupleCriteriaTest.java	2010-01-07 20:41:54 UTC (rev 18444)
@@ -3,72 +3,92 @@
 import java.util.List;
 import javax.persistence.EntityManager;
 import javax.persistence.Tuple;
-import javax.persistence.TupleElement;
 import javax.persistence.criteria.CriteriaBuilder;
 import javax.persistence.criteria.Root;
 import javax.persistence.criteria.CriteriaQuery;
 import javax.persistence.criteria.Path;
 
-import org.hibernate.ejb.test.TestCase;
+import org.hibernate.ejb.metamodel.AbstractMetamodelSpecificTest;
+import org.hibernate.ejb.metamodel.Customer;
+import org.hibernate.ejb.metamodel.Customer_;
 
 /**
  * @author Emmanuel Bernard
  */
-public class TupleCriteriaTest extends TestCase {
+public class TupleCriteriaTest extends AbstractMetamodelSpecificTest {
 	public void testArray() {
 		EntityManager em = factory.createEntityManager();
+		em.getTransaction().begin();
 		Customer c1 = new Customer();
+		c1.setId( "c1" );
 		c1.setAge( 18 );
 		c1.setName( "Bob" );
-		em.getTransaction().begin();
 		em.persist( c1 );
-		em.flush();
+		em.getTransaction().commit();
+		em.close();
 
+		em = factory.createEntityManager();
+		em.getTransaction().begin();
 		final CriteriaBuilder cb = em.getCriteriaBuilder();
 		CriteriaQuery<Object[]> q = cb.createQuery(Object[].class);
 		Root<Customer> c = q.from(Customer.class);
 		q.select( cb.array( c.get(Customer_.name), c.get(Customer_.age) ) );
 		List<Object[]> result = em.createQuery(q).getResultList();
-
 		assertEquals( 1, result.size() );
 		assertEquals( c1.getName(), result.get( 0 )[0] );
 		assertEquals( c1.getAge(), result.get( 0 )[1] );
+		em.getTransaction().commit();
+		em.close();
 
-		em.getTransaction().rollback();
+		em = factory.createEntityManager();
+		em.getTransaction().begin();
+		em.createQuery( "delete Customer" ).executeUpdate();
+		em.getTransaction().commit();
 		em.close();
 	}
 
 
 	public void testTuple() {
 		EntityManager em = factory.createEntityManager();
+
+		em.getTransaction().begin();
 		Customer c1 = new Customer();
+		c1.setId( "c1" );
 		c1.setAge( 18 );
 		c1.setName( "Bob" );
-		em.getTransaction().begin();
 		em.persist( c1 );
-		em.flush();
+		em.getTransaction().commit();
+		em.close();
 
-		final CriteriaBuilder cb = em.getCriteriaBuilder();
+		em = factory.createEntityManager();
+		em.getTransaction().begin();
+		final CriteriaBuilder builder = em.getCriteriaBuilder();
+		CriteriaQuery<Tuple> criteria = builder.createTupleQuery();
+		Root<Customer> customerRoot = criteria.from( Customer.class );
+		Path<String> namePath = customerRoot.get( Customer_.name );
+		Path<Integer> agePath = customerRoot.get( Customer_.age );
+		agePath.alias( "age" );
+		criteria.multiselect( namePath, agePath );
+		List<Tuple> results = em.createQuery( criteria ).getResultList();
+		assertEquals( 1, results.size() );
+		Object resultElement = results.get( 0 );
+		assertTrue( "Check  result 'row' as Tuple", Tuple.class.isInstance( resultElement ) );
+		Tuple resultElementTuple = (Tuple) resultElement;
+		Object[] tupleArray = resultElementTuple.toArray();
+		assertEquals( 2, tupleArray.length );
+		assertEquals( tupleArray[0], resultElementTuple.get( 0 ) );
+		assertEquals( resultElementTuple.get( namePath ), resultElementTuple.get( 0 ) );
+		assertEquals( tupleArray[1], resultElementTuple.get( 1 ) );
+		assertEquals( resultElementTuple.get( agePath ), resultElementTuple.get( 1 ) );
+		assertEquals( resultElementTuple.get( agePath ), resultElementTuple.get( "age" ) );
+		em.getTransaction().commit();
+		em.close();
 
-		CriteriaQuery<Tuple> q = cb.createTupleQuery();
-		Root<Customer> c = q.from(Customer.class);
-		Path<String> tname = c.get(Customer_.name);
-		q.multiselect(  tname, c.get(Customer_.age).alias("age") );
-		List<Tuple> result = em.createQuery(q).getResultList();
-
-		assertEquals( 1, result.size() );
-		//FIXME uncomment when HHH-4724 is fixed
-//		assertEquals( c1.getName(), result.get(0).get(tname) );
-//		assertEquals( c1.getAge(), result.get(0).get("age") );
-				
-
-		em.getTransaction().rollback();
+		em = factory.createEntityManager();
+		em.getTransaction().begin();
+		em.createQuery( "delete Customer" ).executeUpdate();
+		em.getTransaction().commit();
 		em.close();
 	}
 
-	public Class[] getAnnotatedClasses() {
-		return new Class[] {
-				Customer.class
-		};
-	}
 }

Modified: core/trunk/entitymanager/src/test/java/org/hibernate/ejb/metamodel/Customer.java
===================================================================
--- core/trunk/entitymanager/src/test/java/org/hibernate/ejb/metamodel/Customer.java	2010-01-07 20:34:59 UTC (rev 18443)
+++ core/trunk/entitymanager/src/test/java/org/hibernate/ejb/metamodel/Customer.java	2010-01-07 20:41:54 UTC (rev 18444)
@@ -45,6 +45,7 @@
 public class Customer implements java.io.Serializable {
 	private String id;
 	private String name;
+	private Integer age;
 	private Address home;
 	private Address work;
 	private Country country;
@@ -96,6 +97,15 @@
 		this.name = v;
 	}
 
+	@Column(name = "AGE")
+	public Integer getAge() {
+		return age;
+	}
+
+	public void setAge(Integer age) {
+		this.age = age;
+	}
+
 	@Embedded
 	public Country getCountry() {
 		return country;



More information about the hibernate-commits mailing list