massive cleanout of the transformers stuff

- add meaningful generic types to stuff
- remove things which weren't used/tested, and seem obsolete
  (and which could not be propertly generified)
This commit is contained in:
Gavin 2022-01-12 12:57:55 +01:00 committed by Steve Ebersole
parent 22457cc74d
commit c43b6ff606
31 changed files with 138 additions and 896 deletions

View File

@ -14,17 +14,17 @@ import jakarta.persistence.Tuple;
import jakarta.persistence.TupleElement;
import org.hibernate.HibernateException;
import org.hibernate.transform.BasicTransformerAdapter;
import org.hibernate.transform.ResultTransformer;
/**
* ResultTransformer adapter for handling Tuple results from Native queries
*
* @author Arnold Galovics
*/
public class NativeQueryTupleTransformer extends BasicTransformerAdapter {
public class NativeQueryTupleTransformer implements ResultTransformer<Tuple> {
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
public Tuple transformTuple(Object[] tuple, String[] aliases) {
return new NativeTupleImpl( tuple, aliases );
}
@ -52,10 +52,10 @@ public class NativeQueryTupleTransformer extends BasicTransformerAdapter {
private static class NativeTupleImpl implements Tuple {
private Object[] tuple;
private final Object[] tuple;
private Map<String, Object> aliasToValue = new LinkedHashMap<>();
private Map<String, String> aliasReferences = new LinkedHashMap<>();
private final Map<String, Object> aliasToValue = new LinkedHashMap<>();
private final Map<String, String> aliasReferences = new LinkedHashMap<>();
public NativeTupleImpl(Object[] tuple, String[] aliases) {
if ( tuple == null ) {

View File

@ -10,7 +10,6 @@ import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.engine.spi.SessionFactoryImplementor;
/**
* Defines the aspects of query definition that apply to all forms of

View File

@ -558,13 +558,13 @@ public interface NativeQuery<T> extends Query<T>, SynchronizeableQuery {
NativeQuery<T> setLockMode(LockModeType lockMode);
@Override
NativeQuery<T> setTupleTransformer(TupleTransformer<T> transformer);
<R> NativeQuery<R> setTupleTransformer(TupleTransformer<R> transformer);
@Override
NativeQuery<T> setResultListTransformer(ResultListTransformer transformer);
NativeQuery<T> setResultListTransformer(ResultListTransformer<T> transformer);
@Override @SuppressWarnings("deprecation")
NativeQuery<T> setResultTransformer(ResultTransformer transformer);
@Override @Deprecated @SuppressWarnings("deprecation")
<S> NativeQuery<S> setResultTransformer(ResultTransformer<S> transformer);
@Override
NativeQuery<T> setParameter(String name, Object value);

View File

@ -303,12 +303,12 @@ public interface Query<R> extends TypedQuery<R>, CommonQueryContract {
/**
* Set a {@link TupleTransformer}
*/
Query<R> setTupleTransformer(TupleTransformer<R> transformer);
<T> Query<T> setTupleTransformer(TupleTransformer<T> transformer);
/**
* Set a {@link ResultListTransformer}
*/
Query<R> setResultListTransformer(ResultListTransformer transformer);
Query<R> setResultListTransformer(ResultListTransformer<R> transformer);
/**
* Get the execution options for this Query. Many of the setter on the Query
@ -807,14 +807,11 @@ public interface Query<R> extends TypedQuery<R>, CommonQueryContract {
// deprecated methods
/**
* @deprecated (since 5.2) Use {@link #setTupleTransformer} or {@link #setResultListTransformer}
* @deprecated Use {@link #setTupleTransformer} or {@link #setResultListTransformer}
*/
@Deprecated
@SuppressWarnings("unchecked")
default Query<R> setResultTransformer(ResultTransformer transformer) {
setTupleTransformer( transformer );
setResultListTransformer( transformer );
return this;
@Deprecated(since = "5.2")
default <T> Query<T> setResultTransformer(ResultTransformer<T> transformer) {
return setTupleTransformer( transformer ).setResultListTransformer( transformer );
}
}

View File

@ -9,15 +9,17 @@ package org.hibernate.query;
import java.util.List;
/**
* Allows defining transformation of the result List from a Query to some
* other form.
* Defines some processing performed on the result {@link List} of a
* {@link org.hibernate.Query} before the result list is returned to
* the caller of {@link org.hibernate.Query#getResultList()}.
*
* @see org.hibernate.transform.ResultTransformer
*
* @author Steve Ebersole
* @author Gavin King
*/
public interface ResultListTransformer {
@FunctionalInterface
public interface ResultListTransformer<T> {
/**
* Here we have an opportunity to perform transformation on the
* query result as a whole. This might be useful to convert from
@ -29,5 +31,5 @@ public interface ResultListTransformer {
*
* @return The transformed result.
*/
List transformList(List resultList);
List<T> transformList(List<T> resultList);
}

View File

@ -8,12 +8,19 @@ package org.hibernate.query;
import org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter;
import java.util.List;
/**
* User hook for applying transformations of the query result tuples (the result "row").
*
* Ultimately, gets wrapped in a {@link RowTransformerTupleTransformerAdapter}
* to adapt the TupleTransformer to the {@link org.hibernate.sql.results.spi.RowTransformer}
* contract, which is the thing actually used to process the results internally.
* Defines some transformation applied to each result of a {@link org.hibernate.Query}
* before the results are packaged as a {@link List} and returned to the caller of
* {@link org.hibernate.Query#getResultList()}. Each query result is received as a
* tuple, that is, as an array of type {@code Object[]}, and may be transformed to
* some other type.
* <p>
* Every {@code TupleTransformer} is automatically wrapped in an instance of
* {@link RowTransformerTupleTransformerAdapter}, adapting it to the
* {@link org.hibernate.sql.results.spi.RowTransformer} contract, which is always
* used to actually process the results internally.
*
* @see org.hibernate.transform.ResultTransformer
* @see org.hibernate.sql.results.spi.RowTransformer
@ -21,6 +28,7 @@ import org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter;
* @author Steve Ebersole
* @author Gavin King
*/
@FunctionalInterface
public interface TupleTransformer<T> {
/**
* Tuples are the elements making up each "row" of the query result.
@ -33,11 +41,4 @@ public interface TupleTransformer<T> {
* @return The transformed row.
*/
T transformTuple(Object[] tuple, String[] aliases);
/**
* How many result elements will this transformation produce?
*/
default int determineNumberOfResultElements(int rawElementCount) {
return rawElementCount;
}
}

View File

@ -97,7 +97,6 @@ import static org.hibernate.jpa.QueryHints.SPEC_HINT_TIMEOUT;
/**
* @author Steve Ebersole
*/
@SuppressWarnings("WeakerAccess")
public abstract class AbstractQuery<R> implements QueryImplementor<R> {
protected static final EntityManagerMessageLogger log = HEMLogging.messageLogger( AbstractQuery.class );
@ -201,15 +200,15 @@ public abstract class AbstractQuery<R> implements QueryImplementor<R> {
return this;
}
@Override
@SuppressWarnings( "rawtypes" )
public QueryImplementor<R> setTupleTransformer(TupleTransformer transformer) {
@Override @SuppressWarnings("unchecked")
public <T> QueryImplementor<T> setTupleTransformer(TupleTransformer<T> transformer) {
getQueryOptions().setTupleTransformer( transformer );
return this;
// this is bad, we should really return a new instance:
return (QueryImplementor<T>) this;
}
@Override
public QueryImplementor<R> setResultListTransformer(ResultListTransformer transformer) {
public QueryImplementor<R> setResultListTransformer(ResultListTransformer<R> transformer) {
getQueryOptions().setResultListTransformer( transformer );
return this;
}

View File

@ -22,6 +22,8 @@ import org.hibernate.query.QueryParameter;
import jakarta.persistence.Parameter;
import jakarta.persistence.TemporalType;
import org.hibernate.query.ResultListTransformer;
import org.hibernate.query.TupleTransformer;
/**
* @author Steve Ebersole
@ -46,6 +48,12 @@ public interface QueryImplementor<R> extends Query<R> {
ScrollableResultsImplementor<R> scroll(ScrollMode scrollMode);
@Override
<T> QueryImplementor<T> setTupleTransformer(TupleTransformer<T> transformer);
@Override
QueryImplementor<R> setResultListTransformer(ResultListTransformer<R> transformer);
@Override
QueryImplementor<R> setParameter(String name, Object value);
@ -101,7 +109,7 @@ public interface QueryImplementor<R> extends Query<R> {
QueryImplementor<R> setParameter(Parameter<Date> param, Date value, TemporalType temporalType);
@Override
QueryImplementor<R> setParameterList(String name, Collection values);
QueryImplementor<R> setParameterList(String name, @SuppressWarnings("rawtypes") Collection values);
@Override
<P> QueryImplementor<R> setParameterList(String name, Collection<? extends P> values, Class<P> javaType);
@ -119,7 +127,7 @@ public interface QueryImplementor<R> extends Query<R> {
<P> QueryImplementor<R> setParameterList(String name, P[] values, BindableType<P> type);
@Override
QueryImplementor<R> setParameterList(int position, Collection values);
QueryImplementor<R> setParameterList(int position, @SuppressWarnings("rawtypes") Collection values);
@Override
<P> QueryImplementor<R> setParameterList(int position, Collection<? extends P> values, Class<P> javaType);
@ -158,5 +166,5 @@ public interface QueryImplementor<R> extends Query<R> {
QueryImplementor<R> setProperties(Object bean);
@Override
QueryImplementor<R> setProperties(Map bean);
QueryImplementor<R> setProperties(@SuppressWarnings("rawtypes") Map bean);
}

View File

@ -104,7 +104,6 @@ import static org.hibernate.jpa.QueryHints.HINT_NATIVE_LOCKMODE;
/**
* @author Steve Ebersole
*/
@SuppressWarnings("WeakerAccess")
public class NativeQueryImpl<R>
extends AbstractQuery<R>
implements NativeQueryImplementor<R>, DomainQueryExecutionContext, ResultSetMappingResolutionContext {
@ -503,12 +502,12 @@ public class NativeQueryImpl<R>
}
@Override
public NativeQueryImplementor<R> setTupleTransformer(@SuppressWarnings("rawtypes") TupleTransformer transformer) {
return (NativeQueryImplementor<R>) super.setTupleTransformer( transformer );
public <T> NativeQueryImplementor<T> setTupleTransformer(TupleTransformer<T> transformer) {
return (NativeQueryImplementor<T>) super.setTupleTransformer( transformer );
}
@Override
public NativeQueryImplementor<R> setResultListTransformer(ResultListTransformer transformer) {
public NativeQueryImplementor<R> setResultListTransformer(ResultListTransformer<R> transformer) {
return (NativeQueryImplementor<R>) super.setResultListTransformer( transformer );
}
@ -1449,21 +1448,9 @@ public class NativeQueryImpl<R>
return this;
}
@Override @SuppressWarnings("deprecation")
public NativeQueryImplementor<R> setResultTransformer(ResultTransformer transformer) {
super.setResultTransformer( transformer );
return this;
@Override @Deprecated @SuppressWarnings("deprecation")
public <S> NativeQueryImplementor<S> setResultTransformer(ResultTransformer<S> transformer) {
return setTupleTransformer( transformer ).setResultListTransformer( transformer );
}
@Override

View File

@ -190,10 +190,10 @@ public interface NativeQueryImplementor<R> extends QueryImplementor<R>, NativeQu
NativeQueryImplementor<R> addQueryHint(String hint);
@Override
NativeQueryImplementor<R> setTupleTransformer(@SuppressWarnings("rawtypes") TupleTransformer transformer);
<T> NativeQueryImplementor<T> setTupleTransformer(TupleTransformer<T> transformer);
@Override
NativeQueryImplementor<R> setResultListTransformer(ResultListTransformer transformer);
NativeQueryImplementor<R> setResultListTransformer(ResultListTransformer<R> transformer);
@Override
NativeQueryImplementor<R> setParameter(String name, Object val);

View File

@ -32,6 +32,6 @@ public class RowTransformerTupleTransformerAdapter<T> implements RowTransformer<
@Override
public int determineNumberOfResultElements(int rawElementCount) {
return tupleTransformer.determineNumberOfResultElements( rawElementCount );
return rawElementCount;
}
}

View File

@ -5,26 +5,24 @@
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.transform;
import java.lang.reflect.Constructor;
import java.util.List;
import org.hibernate.QueryException;
/**
* Wraps the tuples in a constructor call.
*
* todo : why Alias* in the name???
*/
public class AliasToBeanConstructorResultTransformer implements ResultTransformer {
public class AliasToBeanConstructorResultTransformer<T> implements ResultTransformer<T> {
private final Constructor constructor;
private final Constructor<T> constructor;
/**
* Instantiates a AliasToBeanConstructorResultTransformer.
*
* @param constructor The constructor in which to wrap the tuples.
*/
public AliasToBeanConstructorResultTransformer(Constructor constructor) {
public AliasToBeanConstructorResultTransformer(Constructor<T> constructor) {
this.constructor = constructor;
}
@ -32,7 +30,7 @@ public class AliasToBeanConstructorResultTransformer implements ResultTransforme
* Wrap the incoming tuples in a call to our configured constructor.
*/
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
public T transformTuple(Object[] tuple, String[] aliases) {
try {
return constructor.newInstance( tuple );
}
@ -44,11 +42,6 @@ public class AliasToBeanConstructorResultTransformer implements ResultTransforme
}
}
@Override
public List transformList(List collection) {
return collection;
}
/**
* Define our hashCode by our defined constructor's hasCode.
*
@ -69,6 +62,6 @@ public class AliasToBeanConstructorResultTransformer implements ResultTransforme
@Override
public boolean equals(Object other) {
return other instanceof AliasToBeanConstructorResultTransformer
&& constructor.equals( ( ( AliasToBeanConstructorResultTransformer ) other ).constructor );
&& constructor.equals( ( (AliasToBeanConstructorResultTransformer<?>) other ).constructor );
}
}

View File

@ -19,34 +19,21 @@ import org.hibernate.property.access.spi.Setter;
* Result transformer that allows to transform a result to
* a user specified class which will be populated via setter
* methods or fields matching the alias names.
* <p/>
* <pre>
* List resultWithAliasedBean = s.createCriteria(Enrolment.class)
* .createAlias("student", "st")
* .createAlias("course", "co")
* .setProjection( Projections.projectionList()
* .add( Projections.property("co.description"), "courseDescription" )
* )
* .setResultTransformer( new AliasToBeanResultTransformer(StudentDTO.class) )
* .list();
* <p/>
* StudentDTO dto = (StudentDTO)resultWithAliasedBean.get(0);
* </pre>
*
* @author max
*/
public class AliasToBeanResultTransformer extends AliasedTupleSubsetResultTransformer {
public class AliasToBeanResultTransformer<T> implements ResultTransformer<T> {
// IMPL NOTE : due to the delayed population of setters (setters cached
// for performance), we really cannot properly define equality for
// this transformer
private final Class resultClass;
private final Class<T> resultClass;
private boolean isInitialized;
private String[] aliases;
private Setter[] setters;
public AliasToBeanResultTransformer(Class resultClass) {
public AliasToBeanResultTransformer(Class<T> resultClass) {
if ( resultClass == null ) {
throw new IllegalArgumentException( "resultClass cannot be null" );
}
@ -55,13 +42,8 @@ public class AliasToBeanResultTransformer extends AliasedTupleSubsetResultTransf
}
@Override
public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
return false;
}
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
Object result;
public T transformTuple(Object[] tuple, String[] aliases) {
T result;
try {
if ( ! isInitialized ) {
@ -121,16 +103,10 @@ public class AliasToBeanResultTransformer extends AliasedTupleSubsetResultTransf
return false;
}
AliasToBeanResultTransformer that = ( AliasToBeanResultTransformer ) o;
AliasToBeanResultTransformer<?> that = (AliasToBeanResultTransformer<?>) o;
if ( ! resultClass.equals( that.resultClass ) ) {
return false;
}
if ( ! Arrays.equals( aliases, that.aliases ) ) {
return false;
}
return true;
return resultClass.equals( that.resultClass )
&& Arrays.equals( aliases, that.aliases );
}
@Override

View File

@ -12,14 +12,11 @@ import org.hibernate.internal.util.collections.CollectionHelper;
/**
* {@link ResultTransformer} implementation which builds a map for each "row",
* made up of each aliased value where the alias is the map key.
* <p/>
* Since this transformer is stateless, all instances would be considered equal.
* So for optimization purposes we limit it to a single, singleton {@link #INSTANCE instance}.
*
* @author Gavin King
* @author Steve Ebersole
*/
public class AliasToEntityMapResultTransformer extends AliasedTupleSubsetResultTransformer {
public class AliasToEntityMapResultTransformer implements ResultTransformer<Map<String,Object>> {
public static final AliasToEntityMapResultTransformer INSTANCE = new AliasToEntityMapResultTransformer();
@ -30,8 +27,8 @@ public class AliasToEntityMapResultTransformer extends AliasedTupleSubsetResultT
}
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
Map result = CollectionHelper.mapOfSize( tuple.length );
public Map<String,Object> transformTuple(Object[] tuple, String[] aliases) {
Map<String,Object> result = CollectionHelper.mapOfSize( tuple.length );
for ( int i = 0; i < tuple.length; i++ ) {
String alias = aliases[i];
if ( alias != null ) {
@ -41,11 +38,6 @@ public class AliasToEntityMapResultTransformer extends AliasedTupleSubsetResultT
return result;
}
@Override
public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
return false;
}
/**
* Serialization hook for ensuring singleton uniqueing.
*

View File

@ -1,38 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.transform;
/**
* An implementation of TupleSubsetResultTransformer that ignores a
* tuple element if its corresponding alias is null.
*
* @author Gail Badner
*/
public abstract class AliasedTupleSubsetResultTransformer
extends BasicTransformerAdapter
implements TupleSubsetResultTransformer {
@Override
public boolean[] includeInTransform(String[] aliases, int tupleLength) {
if ( aliases == null ) {
throw new IllegalArgumentException( "aliases cannot be null" );
}
if ( aliases.length != tupleLength ) {
throw new IllegalArgumentException(
"aliases and tupleLength must have the same length; " +
"aliases.length=" + aliases.length + "; tupleLength=" + tupleLength
);
}
boolean[] includeInTransform = new boolean[tupleLength];
for ( int i = 0 ; i < aliases.length ; i++ ) {
if ( aliases[ i ] != null ) {
includeInTransform[ i ] = true;
}
}
return includeInTransform;
}
}

View File

@ -1,23 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.transform;
import java.util.List;
/**
* Provides the basic "noop" impls of the {@link ResultTransformer} contract.
*
* @author Steve Ebersole
*/
public abstract class BasicTransformerAdapter implements ResultTransformer {
public Object transformTuple(Object[] tuple, String[] aliases) {
return tuple;
}
public List transformList(List list) {
return list;
}
}

View File

@ -1,318 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.transform;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.type.Type;
/**
* A ResultTransformer that is used to transform tuples to a value(s)
* that can be cached.
*
* @author Gail Badner
*/
public class CacheableResultTransformer implements ResultTransformer {
// would be nice to be able to have this class extend
// PassThroughResultTransformer, but the default constructor
// is private (as it should be for a singleton)
private final static PassThroughResultTransformer ACTUAL_TRANSFORMER =
PassThroughResultTransformer.INSTANCE;
private final int tupleLength;
private final int tupleSubsetLength;
// array with the i-th element indicating whether the i-th
// expression returned by a query is included in the tuple;
// IMPLEMENTATION NOTE:
// "joined" and "fetched" associations may use the same SQL,
// but result in different tuple and cached values. This is
// because "fetched" associations are excluded from the tuple.
// includeInTuple provides a way to distinguish these 2 cases.
private final boolean[] includeInTuple;
// indexes for tuple that are included in the transformation;
// set to null if all elements in the tuple are included
private final int[] includeInTransformIndex;
/**
* Returns a CacheableResultTransformer that is used to transform
* tuples to a value(s) that can be cached.
*
* @param transformer - result transformer that will ultimately be
* be used (after caching results)
* @param aliases - the aliases that correspond to the tuple;
* if it is non-null, its length must equal the number
* of true elements in includeInTuple[]
* @param includeInTuple - array with the i-th element indicating
* whether the i-th expression returned by a query is
* included in the tuple; the number of true values equals
* the length of the tuple that will be transformed;
* must be non-null
*
* @return a CacheableResultTransformer that is used to transform
* tuples to a value(s) that can be cached.
*/
public static CacheableResultTransformer create(
ResultTransformer transformer,
String[] aliases,
boolean[] includeInTuple) {
return transformer instanceof TupleSubsetResultTransformer
? create( ( TupleSubsetResultTransformer ) transformer, aliases, includeInTuple )
: create( includeInTuple );
}
/**
* Returns a CacheableResultTransformer that is used to transform
* tuples to a value(s) that can be cached.
*
* @param transformer - a tuple subset result transformer;
* must be non-null;
* @param aliases - the aliases that correspond to the tuple;
* if it is non-null, its length must equal the number
* of true elements in includeInTuple[]
* @param includeInTuple - array with the i-th element indicating
* whether the i-th expression returned by a query is
* included in the tuple; the number of true values equals
* the length of the tuple that will be transformed;
* must be non-null
*
* @return a CacheableResultTransformer that is used to transform
* tuples to a value(s) that can be cached.
*/
private static CacheableResultTransformer create(
TupleSubsetResultTransformer transformer,
String[] aliases,
boolean[] includeInTuple) {
if ( transformer == null ) {
throw new IllegalArgumentException( "transformer cannot be null" );
}
int tupleLength = ArrayHelper.countTrue( includeInTuple );
if ( aliases != null && aliases.length != tupleLength ) {
throw new IllegalArgumentException(
"if aliases are not null, then the length of aliases must equal the number of true elements in includeInTuple; " +
"aliases.length=" + aliases.length + "; tupleLength=" + tupleLength
);
}
return new CacheableResultTransformer(
includeInTuple,
transformer.includeInTransform( aliases, tupleLength )
);
}
/**
* Returns a CacheableResultTransformer that is used to transform
* tuples to a value(s) that can be cached.
*
* @param includeInTuple - array with the i-th element indicating
* whether the i-th expression returned by a query is
* included in the tuple; the number of true values equals
* the length of the tuple that will be transformed;
* must be non-null
*
* @return a CacheableResultTransformer that is used to transform
* tuples to a value(s) that can be cached.
*/
private static CacheableResultTransformer create(boolean[] includeInTuple) {
return new CacheableResultTransformer( includeInTuple, null );
}
private CacheableResultTransformer(boolean[] includeInTuple, boolean[] includeInTransform) {
if ( includeInTuple == null ) {
throw new IllegalArgumentException( "includeInTuple cannot be null" );
}
this.includeInTuple = includeInTuple;
tupleLength = ArrayHelper.countTrue( includeInTuple );
tupleSubsetLength = (
includeInTransform == null ?
tupleLength :
ArrayHelper.countTrue( includeInTransform )
);
if ( tupleSubsetLength == tupleLength ) {
includeInTransformIndex = null;
}
else {
includeInTransformIndex = new int[tupleSubsetLength];
for ( int i = 0, j = 0 ; i < includeInTransform.length ; i++ ) {
if ( includeInTransform[ i ] ) {
includeInTransformIndex[ j ] = i;
j++;
}
}
}
}
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
if ( aliases != null && aliases.length != tupleLength ) {
throw new IllegalStateException(
"aliases expected length is " + tupleLength +
"; actual length is " + aliases.length );
}
// really more correct to pass index( aliases.getClass(), aliases )
// as the 2nd arg to the following statement;
// passing null instead because it ends up being ignored.
return ACTUAL_TRANSFORMER.transformTuple( index( tuple.getClass(), tuple ), null );
}
/**
* Re-transforms, if necessary, a List of values previously
* transformed by this (or an equivalent) CacheableResultTransformer.
* Each element of the list is re-transformed in place (i.e, List
* elements are replaced with re-transformed values) and the original
* List is returned.
* <p/>
* If re-transformation is unnecessary, the original List is returned
* unchanged.
*
* @param transformedResults - results that were previously transformed
* @param aliases - the aliases that correspond to the untransformed tuple;
* @param transformer - the transformer for the re-transformation
* @param includeInTuple indicates the indexes of
*
* @return transformedResults, with each element re-transformed (if necessary)
*/
@SuppressWarnings( {"unchecked"})
public List retransformResults(
List transformedResults,
String[] aliases,
ResultTransformer transformer,
boolean[] includeInTuple) {
if ( transformer == null ) {
throw new IllegalArgumentException( "transformer cannot be null" );
}
if ( ! this.equals( create( transformer, aliases, includeInTuple ) ) ) {
throw new IllegalStateException(
"this CacheableResultTransformer is inconsistent with specified arguments; cannot re-transform"
);
}
boolean requiresRetransform = true;
String[] aliasesToUse = aliases == null ? null : index( ( aliases.getClass() ), aliases );
if ( transformer == ACTUAL_TRANSFORMER ) {
requiresRetransform = false;
}
else if ( transformer instanceof TupleSubsetResultTransformer ) {
requiresRetransform = ! ( ( TupleSubsetResultTransformer ) transformer ).isTransformedValueATupleElement(
aliasesToUse,
tupleLength
);
}
if ( requiresRetransform ) {
for ( int i = 0 ; i < transformedResults.size() ; i++ ) {
Object[] tuple = ACTUAL_TRANSFORMER.untransformToTuple(
transformedResults.get( i ),
tupleSubsetLength == 1
);
transformedResults.set( i, transformer.transformTuple( tuple, aliasesToUse ) );
}
}
return transformedResults;
}
/**
* Untransforms, if necessary, a List of values previously
* transformed by this (or an equivalent) CacheableResultTransformer.
* Each element of the list is untransformed in place (i.e, List
* elements are replaced with untransformed values) and the original
* List is returned.
* <p/>
* If not unnecessary, the original List is returned
* unchanged.
* <p/>
* NOTE: If transformed values are a subset of the original
* tuple, then, on return, elements corresponding to
* excluded tuple elements will be null.
* @param results - results that were previously transformed
* @return results, with each element untransformed (if necessary)
*/
@SuppressWarnings( {"unchecked"})
public List untransformToTuples(List results) {
if ( includeInTransformIndex == null ) {
results = ACTUAL_TRANSFORMER.untransformToTuples(
results,
tupleSubsetLength == 1
);
}
else {
for ( int i = 0 ; i < results.size() ; i++ ) {
Object[] tuple = ACTUAL_TRANSFORMER.untransformToTuple(
results.get( i ),
tupleSubsetLength == 1
);
results.set( i, unindex( tuple.getClass(), tuple ) );
}
}
return results;
}
public Type[] getCachedResultTypes(Type[] tupleResultTypes) {
return tupleLength != tupleSubsetLength
? index( tupleResultTypes.getClass(), tupleResultTypes )
: tupleResultTypes;
}
@Override
public List transformList(List list) {
return list;
}
private <T> T[] index(Class<? extends T[]> clazz, T[] objects) {
T[] objectsIndexed = objects;
if ( objects != null &&
includeInTransformIndex != null &&
objects.length != tupleSubsetLength ) {
objectsIndexed = clazz.cast( Array.newInstance( clazz.getComponentType(), tupleSubsetLength ) );
for ( int i = 0 ; i < tupleSubsetLength; i++ ) {
objectsIndexed[ i ] = objects[ includeInTransformIndex[ i ] ];
}
}
return objectsIndexed;
}
private <T> T[] unindex(Class<? extends T[]> clazz, T[] objects) {
T[] objectsUnindexed = objects;
if ( objects != null &&
includeInTransformIndex != null &&
objects.length != tupleLength ) {
objectsUnindexed = clazz.cast( Array.newInstance( clazz.getComponentType(), tupleLength ) );
for ( int i = 0 ; i < tupleSubsetLength; i++ ) {
objectsUnindexed[ includeInTransformIndex[ i ] ] = objects[ i ];
}
}
return objectsUnindexed;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
CacheableResultTransformer that = ( CacheableResultTransformer ) o;
return tupleLength == that.tupleLength
&& tupleSubsetLength == that.tupleSubsetLength
&& Arrays.equals( includeInTuple, that.includeInTuple )
&& Arrays.equals( includeInTransformIndex, that.includeInTransformIndex );
}
@Override
public int hashCode() {
int result = tupleLength;
result = 31 * result + tupleSubsetLength;
result = 31 * result + ( includeInTuple != null ? Arrays.hashCode( includeInTuple ) : 0 );
result = 31 * result + ( includeInTransformIndex != null ? Arrays.hashCode( includeInTransformIndex ) : 0 );
return result;
}
}

View File

@ -1,84 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.transform;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.internal.CoreMessageLogger;
import static org.hibernate.internal.CoreLogging.messageLogger;
/**
* Distinctions the result tuples in the final result based on the defined
* equality of the tuples.
* <p/>
* Since this transformer is stateless, all instances would be considered equal.
* So for optimization purposes we limit it to a single, singleton {@link #INSTANCE instance}.
*
* @author Steve Ebersole
*/
public class DistinctResultTransformer extends BasicTransformerAdapter {
public static final DistinctResultTransformer INSTANCE = new DistinctResultTransformer();
private static final CoreMessageLogger LOG = messageLogger( DistinctResultTransformer.class );
/**
* Helper class to handle distincting
*/
private static final class Identity {
final Object entity;
private Identity(Object entity) {
this.entity = entity;
}
@Override
public boolean equals(Object other) {
return Identity.class.isInstance( other )
&& this.entity == ( (Identity) other ).entity;
}
@Override
public int hashCode() {
return System.identityHashCode( entity );
}
}
/**
* Disallow instantiation of DistinctResultTransformer.
*/
private DistinctResultTransformer() {
}
/**
* Uniquely distinct each tuple row here.
*/
@Override
public List transformList(List list) {
List<Object> result = new ArrayList<>( list.size() );
Set<Identity> distinct = new HashSet<>();
for ( Object entity : list ) {
if ( distinct.add( new Identity( entity ) ) ) {
result.add( entity );
}
}
LOG.debugf( "Transformed: %s rows to: %s distinct results", list.size(), result.size() );
return result;
}
/**
* Serialization hook for ensuring singleton uniqueing.
*
* @return The singleton instance : {@link #INSTANCE}
*/
private Object readResolve() {
return INSTANCE;
}
}

View File

@ -1,72 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.transform;
import java.util.List;
/**
* Much like {@link RootEntityResultTransformer}, but we also distinct
* the entity in the final result.
* <p/>
* Since this transformer is stateless, all instances would be considered equal.
* So for optimization purposes we limit it to a single, singleton {@link #INSTANCE instance}.
*
* @author Gavin King
* @author Steve Ebersole
*/
public class DistinctRootEntityResultTransformer implements TupleSubsetResultTransformer {
public static final DistinctRootEntityResultTransformer INSTANCE = new DistinctRootEntityResultTransformer();
/**
* Disallow instantiation of DistinctRootEntityResultTransformer.
*/
private DistinctRootEntityResultTransformer() {
}
/**
* Simply delegates to {@link RootEntityResultTransformer#transformTuple}.
*
* @param tuple The tuple to transform
* @param aliases The tuple aliases
* @return The transformed tuple row.
*/
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return RootEntityResultTransformer.INSTANCE.transformTuple( tuple, aliases );
}
/**
* Simply delegates to {@link DistinctResultTransformer#transformList}.
*
* @param list The list to transform.
* @return The transformed List.
*/
@Override
public List transformList(List list) {
return DistinctResultTransformer.INSTANCE.transformList( list );
}
@Override
public boolean[] includeInTransform(String[] aliases, int tupleLength) {
return RootEntityResultTransformer.INSTANCE.includeInTransform( aliases, tupleLength );
}
@Override
public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
return RootEntityResultTransformer.INSTANCE.isTransformedValueATupleElement( null, tupleLength );
}
/**
* Serialization hook for ensuring singleton uniqueing.
*
* @return The singleton instance : {@link #INSTANCE}
*/
private Object readResolve() {
return INSTANCE;
}
}

View File

@ -1,69 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.transform;
import java.util.Arrays;
import java.util.List;
/**
* ???
*
* @author max
*/
public class PassThroughResultTransformer extends BasicTransformerAdapter implements TupleSubsetResultTransformer {
public static final PassThroughResultTransformer INSTANCE = new PassThroughResultTransformer();
/**
* Disallow instantiation of PassThroughResultTransformer.
*/
private PassThroughResultTransformer() {
}
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return tuple.length==1 ? tuple[0] : tuple;
}
@Override
public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
return tupleLength == 1;
}
@Override
public boolean[] includeInTransform(String[] aliases, int tupleLength) {
boolean[] includeInTransformedResult = new boolean[tupleLength];
Arrays.fill( includeInTransformedResult, true );
return includeInTransformedResult;
}
/* package-protected */
List untransformToTuples(List results, boolean isSingleResult) {
// un-transform only if necessary; if transformed, do it in place;
if ( isSingleResult ) {
for ( int i = 0 ; i < results.size() ; i++ ) {
Object[] tuple = untransformToTuple( results.get( i ), isSingleResult);
results.set( i, tuple );
}
}
return results;
}
/* package-protected */
Object[] untransformToTuple(Object transformed, boolean isSingleResult ) {
return isSingleResult ? new Object[] { transformed } : ( Object[] ) transformed;
}
/**
* Serialization hook for ensuring singleton uniqueing.
*
* @return The singleton instance : {@link #INSTANCE}
*/
private Object readResolve() {
return INSTANCE;
}
}

View File

@ -7,6 +7,7 @@
package org.hibernate.transform;
import java.io.Serializable;
import java.util.List;
import org.hibernate.query.Query;
import org.hibernate.query.ResultListTransformer;
@ -20,11 +21,13 @@ import org.hibernate.query.TupleTransformer;
*
* @author Gavin King
*
* @deprecated ResultTransformer is no longer supported. It has been split
* into {@link TupleTransformer} and {@link ResultListTransformer} to define
* functional interfaces.
* @deprecated Use {@link TupleTransformer} and/or {@link ResultListTransformer}
*/
@Deprecated
public interface ResultTransformer extends TupleTransformer, ResultListTransformer, Serializable {
public interface ResultTransformer<T> extends TupleTransformer<T>, ResultListTransformer<T>, Serializable {
@Override
default List<T> transformList(List<T> resultList) {
return resultList;
}
}

View File

@ -1,65 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.transform;
import org.hibernate.internal.util.collections.ArrayHelper;
/**
* {@link ResultTransformer} implementation which limits the result tuple
* to only the "root entity".
* <p/>
* Since this transformer is stateless, all instances would be considered equal.
* So for optimization purposes we limit it to a single, singleton {@link #INSTANCE instance}.
*
* @author Gavin King
* @author Steve Ebersole
*/
public final class RootEntityResultTransformer extends BasicTransformerAdapter implements TupleSubsetResultTransformer {
public static final RootEntityResultTransformer INSTANCE = new RootEntityResultTransformer();
/**
* Disallow instantiation of RootEntityResultTransformer.
*/
private RootEntityResultTransformer() {
}
/**
* Return just the root entity from the row tuple.
*/
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return tuple[ tuple.length-1 ];
}
@Override
public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
return true;
}
@Override
public boolean[] includeInTransform(String[] aliases, int tupleLength) {
boolean[] includeInTransform;
if ( tupleLength == 1 ) {
includeInTransform = ArrayHelper.TRUE;
}
else {
includeInTransform = new boolean[tupleLength];
includeInTransform[ tupleLength - 1 ] = true;
}
return includeInTransform;
}
/**
* Serialization hook for ensuring singleton uniqueing.
*
* @return The singleton instance : {@link #INSTANCE}
*/
private Object readResolve() {
return INSTANCE;
}
}

View File

@ -7,11 +7,12 @@
package org.hibernate.transform;
import java.util.Arrays;
import java.util.List;
/**
* Transforms each result row from a tuple into a {@link java.util.List} whose elements are each tuple value
* Transforms each result row from a tuple into a {@link List} whose elements are each tuple value
*/
public class ToListResultTransformer extends BasicTransformerAdapter {
public class ToListResultTransformer implements ResultTransformer<List<Object>> {
public static final ToListResultTransformer INSTANCE = new ToListResultTransformer();
/**
@ -21,7 +22,7 @@ public class ToListResultTransformer extends BasicTransformerAdapter {
}
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
public List<Object> transformTuple(Object[] tuple, String[] aliases) {
return Arrays.asList( tuple );
}

View File

@ -26,8 +26,8 @@ final public class Transformers {
* Creates a ResultTransformer that will inject aliased values into
* instances of Class via property methods or fields.
*/
public static ResultTransformer aliasToBean(Class target) {
return new AliasToBeanResultTransformer(target);
public static <T> ResultTransformer<T> aliasToBean(Class<T> target) {
return new AliasToBeanResultTransformer<>(target);
}
}

View File

@ -1,67 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.transform;
/**
* A ResultTransformer that operates on "well-defined" and consistent
* subset of a tuple's elements.
*
* "Well-defined" means that:
* <ol>
* <li>
* the indexes of tuple elements accessed by a
* TupleSubsetResultTransformer depends only on the aliases
* and the number of elements in the tuple; i.e, it does
* not depend on the value of the tuple being transformed;
* </li>
* <li>
* any tuple elements included in the transformed value are
* unmodified by the transformation;
* </li>
* <li>
* transforming equivalent tuples with the same aliases multiple
* times results in transformed values that are equivalent;
* </li>
* <li>
* the result of transforming the tuple subset (only those
* elements accessed by the transformer) using only the
* corresponding aliases is equivalent to transforming the
* full tuple with the full array of aliases;
* </li>
* <li>
* the result of transforming a tuple with non-accessed tuple
* elements and corresponding aliases set to null
* is equivalent to transforming the full tuple with the
* full array of aliases;
* </li>
* </ol>
*
* @author Gail Badner
*/
public interface TupleSubsetResultTransformer extends ResultTransformer {
/**
* When a tuple is transformed, is the result a single element of the tuple?
*
* @param aliases - the aliases that correspond to the tuple
* @param tupleLength - the number of elements in the tuple
* @return true, if the transformed value is a single element of the tuple;
* false, otherwise.
*/
boolean isTransformedValueATupleElement(String[] aliases, int tupleLength);
/**
* Returns an array with the i-th element indicating whether the i-th
* element of the tuple is included in the transformed value.
*
* @param aliases - the aliases that correspond to the tuple
* @param tupleLength - the number of elements in the tuple
* @return array with the i-th element indicating whether the i-th
* element of the tuple is included in the transformed value.
*/
boolean[] includeInTransform(String[] aliases, int tupleLength);
}

View File

@ -27,12 +27,12 @@ import org.hibernate.cache.spi.entry.CollectionCacheEntry;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.Query;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.hibernate.transform.ResultTransformer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -808,14 +808,18 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase {
criteria.where( criteriaBuilder.equal( root.get( "id" ), testData.prod1Id ) );
Product prod = session.createQuery( criteria )
.setResultTransformer( DistinctRootEntityResultTransformer.INSTANCE )
.setResultTransformer(new ResultTransformer<Product>() {
@Override
public Product transformTuple(Object[] tuple, String[] aliases) {
return (Product) tuple[0];
}
@Override
public List<Product> transformList(List<Product> resultList) {
return ResultTransformer.super.transformList(resultList);
}
})
.uniqueResult();
// Product prod = ( Product ) session.createCriteria( Product.class )
// .setResultTransformer( DistinctRootEntityResultTransformer.INSTANCE )
// .add( Restrictions.eq( "id", testData.prod1Id ) )
// .uniqueResult();
assertNotNull( prod );
assertEquals( "Incorrect Product.categories count for filter", 1, prod.getCategories().size() );
}

View File

@ -56,7 +56,7 @@ import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.stat.QueryStatistics;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.transform.Transformers;
import org.hibernate.testing.DialectChecks;
@ -3572,7 +3572,12 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
t = session.beginTransaction();
results = session.createQuery( "select a from Animal a, Animal b order by a.id" )
.setResultTransformer( DistinctRootEntityResultTransformer.INSTANCE )
.setResultTransformer(new ResultTransformer() {
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return tuple[0];
}
})
.list();
assertEquals( "Incorrect result size", 2, results.size());
assertTrue( "Incorrect return type", results.get( 0 ) instanceof Animal );

View File

@ -7,6 +7,7 @@
package org.hibernate.orm.test.hqlfetchscroll;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@ -14,12 +15,12 @@ import java.util.Set;
import org.hibernate.Hibernate;
import org.hibernate.ScrollableResults;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.transform.ResultTransformer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -43,7 +44,16 @@ public class HQLScrollFetchTest {
scope.inTransaction(
session -> {
List list = session.createQuery( QUERY )
.setResultTransformer( DistinctRootEntityResultTransformer.INSTANCE )
.setResultTransformer(new ResultTransformer() {
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return tuple[0];
}
@Override
public List transformList(List resultList) {
return Arrays.asList( new HashSet(resultList).toArray() );
}
})
.list();
assertResultFromAllUsers( list );
}

View File

@ -8,7 +8,7 @@ package org.hibernate.orm.test.jpa.compliance.tck2_2;
import java.util.ArrayList;
import java.util.List;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
@ -17,9 +17,9 @@ import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import org.hibernate.boot.MetadataSources;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.hibernate.transform.ResultTransformer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -47,7 +47,12 @@ public class QueryExecutionTest extends BaseNonConfigCoreFunctionalTestCase {
assertThat( distinctResult.size(), CoreMatchers.is( 1 ) );
final List distinctViaTransformerResult = session.createQuery( "select c from Customer c join fetch c.orders" )
.setResultTransformer( DistinctRootEntityResultTransformer.INSTANCE ).list();
.setResultTransformer(new ResultTransformer() {
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return tuple[0];
}
}).list();
assertThat( distinctResult.size(), CoreMatchers.is( 1 ) );
}
);

View File

@ -66,12 +66,6 @@ public class ResultTransformerTest extends BaseCoreFunctionalTestCase {
// return only the PartnerA object from the query
return arg0[1];
}
@SuppressWarnings("unchecked")
public List transformList(List arg0)
{
return arg0;
}
});
ScrollableResults sr = q.scroll();
// HANA supports only ResultSet.TYPE_FORWARD_ONLY and

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.test.sql.hand.query;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
@ -36,8 +35,7 @@ import org.hibernate.orm.test.sql.hand.Speech;
import org.hibernate.orm.test.sql.hand.TextHolder;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.Query;
import org.hibernate.transform.BasicTransformerAdapter;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.transform.Transformers;
import org.hibernate.type.StandardBasicTypes;
@ -215,7 +213,12 @@ public class NativeSQLQueriesTest {
" left outer join EMPLOYMENT emp on org.ORGID = emp.EMPLOYER, ORGANIZATION org2" )
.addEntity("org", Organization.class)
.addJoin("emp", "org.employments")
.setResultTransformer( DistinctRootEntityResultTransformer.INSTANCE )
.setResultTransformer(new ResultTransformer() {
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
return tuple[0];
}
})
.list();
assertEquals( l.size(), 2 );
}
@ -893,10 +896,9 @@ public class NativeSQLQueriesTest {
return on ? ( byte ) 1 : ( byte ) 0;
}
@SuppressWarnings( {"unchecked"})
private static class UpperCasedAliasToEntityMapResultTransformer extends BasicTransformerAdapter implements Serializable {
private static class UpperCasedAliasToEntityMapResultTransformer implements ResultTransformer<Object> {
public Object transformTuple(Object[] tuple, String[] aliases) {
Map result = new HashMap( tuple.length );
Map<String,Object> result = new HashMap<>( tuple.length );
for ( int i = 0; i < tuple.length; i++ ) {
String alias = aliases[i];
if ( alias != null ) {