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

View File

@ -10,7 +10,6 @@ import org.hibernate.CacheMode;
import org.hibernate.FlushMode; import org.hibernate.FlushMode;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.engine.spi.SessionFactoryImplementor;
/** /**
* Defines the aspects of query definition that apply to all forms of * 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); NativeQuery<T> setLockMode(LockModeType lockMode);
@Override @Override
NativeQuery<T> setTupleTransformer(TupleTransformer<T> transformer); <R> NativeQuery<R> setTupleTransformer(TupleTransformer<R> transformer);
@Override @Override
NativeQuery<T> setResultListTransformer(ResultListTransformer transformer); NativeQuery<T> setResultListTransformer(ResultListTransformer<T> transformer);
@Override @SuppressWarnings("deprecation") @Override @Deprecated @SuppressWarnings("deprecation")
NativeQuery<T> setResultTransformer(ResultTransformer transformer); <S> NativeQuery<S> setResultTransformer(ResultTransformer<S> transformer);
@Override @Override
NativeQuery<T> setParameter(String name, Object value); 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} * Set a {@link TupleTransformer}
*/ */
Query<R> setTupleTransformer(TupleTransformer<R> transformer); <T> Query<T> setTupleTransformer(TupleTransformer<T> transformer);
/** /**
* Set a {@link ResultListTransformer} * 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 * 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 methods
/** /**
* @deprecated (since 5.2) Use {@link #setTupleTransformer} or {@link #setResultListTransformer} * @deprecated Use {@link #setTupleTransformer} or {@link #setResultListTransformer}
*/ */
@Deprecated @Deprecated(since = "5.2")
@SuppressWarnings("unchecked") default <T> Query<T> setResultTransformer(ResultTransformer<T> transformer) {
default Query<R> setResultTransformer(ResultTransformer transformer) { return setTupleTransformer( transformer ).setResultListTransformer( transformer );
setTupleTransformer( transformer );
setResultListTransformer( transformer );
return this;
} }
} }

View File

@ -9,15 +9,17 @@ package org.hibernate.query;
import java.util.List; import java.util.List;
/** /**
* Allows defining transformation of the result List from a Query to some * Defines some processing performed on the result {@link List} of a
* other form. * {@link org.hibernate.Query} before the result list is returned to
* the caller of {@link org.hibernate.Query#getResultList()}.
* *
* @see org.hibernate.transform.ResultTransformer * @see org.hibernate.transform.ResultTransformer
* *
* @author Steve Ebersole * @author Steve Ebersole
* @author Gavin King * @author Gavin King
*/ */
public interface ResultListTransformer { @FunctionalInterface
public interface ResultListTransformer<T> {
/** /**
* Here we have an opportunity to perform transformation on the * Here we have an opportunity to perform transformation on the
* query result as a whole. This might be useful to convert from * query result as a whole. This might be useful to convert from
@ -29,5 +31,5 @@ public interface ResultListTransformer {
* *
* @return The transformed result. * @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 org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter;
import java.util.List;
/** /**
* User hook for applying transformations of the query result tuples (the result "row"). * 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
* Ultimately, gets wrapped in a {@link RowTransformerTupleTransformerAdapter} * {@link org.hibernate.Query#getResultList()}. Each query result is received as a
* to adapt the TupleTransformer to the {@link org.hibernate.sql.results.spi.RowTransformer} * tuple, that is, as an array of type {@code Object[]}, and may be transformed to
* contract, which is the thing actually used to process the results internally. * 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.transform.ResultTransformer
* @see org.hibernate.sql.results.spi.RowTransformer * @see org.hibernate.sql.results.spi.RowTransformer
@ -21,6 +28,7 @@ import org.hibernate.sql.results.internal.RowTransformerTupleTransformerAdapter;
* @author Steve Ebersole * @author Steve Ebersole
* @author Gavin King * @author Gavin King
*/ */
@FunctionalInterface
public interface TupleTransformer<T> { public interface TupleTransformer<T> {
/** /**
* Tuples are the elements making up each "row" of the query result. * Tuples are the elements making up each "row" of the query result.
@ -33,11 +41,4 @@ public interface TupleTransformer<T> {
* @return The transformed row. * @return The transformed row.
*/ */
T transformTuple(Object[] tuple, String[] aliases); 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 * @author Steve Ebersole
*/ */
@SuppressWarnings("WeakerAccess")
public abstract class AbstractQuery<R> implements QueryImplementor<R> { public abstract class AbstractQuery<R> implements QueryImplementor<R> {
protected static final EntityManagerMessageLogger log = HEMLogging.messageLogger( AbstractQuery.class ); protected static final EntityManagerMessageLogger log = HEMLogging.messageLogger( AbstractQuery.class );
@ -201,15 +200,15 @@ public abstract class AbstractQuery<R> implements QueryImplementor<R> {
return this; return this;
} }
@Override @Override @SuppressWarnings("unchecked")
@SuppressWarnings( "rawtypes" ) public <T> QueryImplementor<T> setTupleTransformer(TupleTransformer<T> transformer) {
public QueryImplementor<R> setTupleTransformer(TupleTransformer transformer) {
getQueryOptions().setTupleTransformer( transformer ); getQueryOptions().setTupleTransformer( transformer );
return this; // this is bad, we should really return a new instance:
return (QueryImplementor<T>) this;
} }
@Override @Override
public QueryImplementor<R> setResultListTransformer(ResultListTransformer transformer) { public QueryImplementor<R> setResultListTransformer(ResultListTransformer<R> transformer) {
getQueryOptions().setResultListTransformer( transformer ); getQueryOptions().setResultListTransformer( transformer );
return this; return this;
} }

View File

@ -22,6 +22,8 @@ import org.hibernate.query.QueryParameter;
import jakarta.persistence.Parameter; import jakarta.persistence.Parameter;
import jakarta.persistence.TemporalType; import jakarta.persistence.TemporalType;
import org.hibernate.query.ResultListTransformer;
import org.hibernate.query.TupleTransformer;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -46,6 +48,12 @@ public interface QueryImplementor<R> extends Query<R> {
ScrollableResultsImplementor<R> scroll(ScrollMode scrollMode); ScrollableResultsImplementor<R> scroll(ScrollMode scrollMode);
@Override
<T> QueryImplementor<T> setTupleTransformer(TupleTransformer<T> transformer);
@Override
QueryImplementor<R> setResultListTransformer(ResultListTransformer<R> transformer);
@Override @Override
QueryImplementor<R> setParameter(String name, Object value); 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); QueryImplementor<R> setParameter(Parameter<Date> param, Date value, TemporalType temporalType);
@Override @Override
QueryImplementor<R> setParameterList(String name, Collection values); QueryImplementor<R> setParameterList(String name, @SuppressWarnings("rawtypes") Collection values);
@Override @Override
<P> QueryImplementor<R> setParameterList(String name, Collection<? extends P> values, Class<P> javaType); <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); <P> QueryImplementor<R> setParameterList(String name, P[] values, BindableType<P> type);
@Override @Override
QueryImplementor<R> setParameterList(int position, Collection values); QueryImplementor<R> setParameterList(int position, @SuppressWarnings("rawtypes") Collection values);
@Override @Override
<P> QueryImplementor<R> setParameterList(int position, Collection<? extends P> values, Class<P> javaType); <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); QueryImplementor<R> setProperties(Object bean);
@Override @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 * @author Steve Ebersole
*/ */
@SuppressWarnings("WeakerAccess")
public class NativeQueryImpl<R> public class NativeQueryImpl<R>
extends AbstractQuery<R> extends AbstractQuery<R>
implements NativeQueryImplementor<R>, DomainQueryExecutionContext, ResultSetMappingResolutionContext { implements NativeQueryImplementor<R>, DomainQueryExecutionContext, ResultSetMappingResolutionContext {
@ -503,12 +502,12 @@ public class NativeQueryImpl<R>
} }
@Override @Override
public NativeQueryImplementor<R> setTupleTransformer(@SuppressWarnings("rawtypes") TupleTransformer transformer) { public <T> NativeQueryImplementor<T> setTupleTransformer(TupleTransformer<T> transformer) {
return (NativeQueryImplementor<R>) super.setTupleTransformer( transformer ); return (NativeQueryImplementor<T>) super.setTupleTransformer( transformer );
} }
@Override @Override
public NativeQueryImplementor<R> setResultListTransformer(ResultListTransformer transformer) { public NativeQueryImplementor<R> setResultListTransformer(ResultListTransformer<R> transformer) {
return (NativeQueryImplementor<R>) super.setResultListTransformer( transformer ); return (NativeQueryImplementor<R>) super.setResultListTransformer( transformer );
} }
@ -1449,21 +1448,9 @@ public class NativeQueryImpl<R>
return this; return this;
} }
@Override @Deprecated @SuppressWarnings("deprecation")
public <S> NativeQueryImplementor<S> setResultTransformer(ResultTransformer<S> transformer) {
return setTupleTransformer( transformer ).setResultListTransformer( transformer );
@Override @SuppressWarnings("deprecation")
public NativeQueryImplementor<R> setResultTransformer(ResultTransformer transformer) {
super.setResultTransformer( transformer );
return this;
} }
@Override @Override

View File

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

View File

@ -32,6 +32,6 @@ public class RowTransformerTupleTransformerAdapter<T> implements RowTransformer<
@Override @Override
public int determineNumberOfResultElements(int rawElementCount) { 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>. * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/ */
package org.hibernate.transform; package org.hibernate.transform;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.util.List;
import org.hibernate.QueryException; import org.hibernate.QueryException;
/** /**
* Wraps the tuples in a constructor call. * 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. * Instantiates a AliasToBeanConstructorResultTransformer.
* *
* @param constructor The constructor in which to wrap the tuples. * @param constructor The constructor in which to wrap the tuples.
*/ */
public AliasToBeanConstructorResultTransformer(Constructor constructor) { public AliasToBeanConstructorResultTransformer(Constructor<T> constructor) {
this.constructor = constructor; this.constructor = constructor;
} }
@ -32,7 +30,7 @@ public class AliasToBeanConstructorResultTransformer implements ResultTransforme
* Wrap the incoming tuples in a call to our configured constructor. * Wrap the incoming tuples in a call to our configured constructor.
*/ */
@Override @Override
public Object transformTuple(Object[] tuple, String[] aliases) { public T transformTuple(Object[] tuple, String[] aliases) {
try { try {
return constructor.newInstance( tuple ); 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. * Define our hashCode by our defined constructor's hasCode.
* *
@ -69,6 +62,6 @@ public class AliasToBeanConstructorResultTransformer implements ResultTransforme
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
return other instanceof AliasToBeanConstructorResultTransformer 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 * Result transformer that allows to transform a result to
* a user specified class which will be populated via setter * a user specified class which will be populated via setter
* methods or fields matching the alias names. * 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 * @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 // IMPL NOTE : due to the delayed population of setters (setters cached
// for performance), we really cannot properly define equality for // for performance), we really cannot properly define equality for
// this transformer // this transformer
private final Class resultClass; private final Class<T> resultClass;
private boolean isInitialized; private boolean isInitialized;
private String[] aliases; private String[] aliases;
private Setter[] setters; private Setter[] setters;
public AliasToBeanResultTransformer(Class resultClass) { public AliasToBeanResultTransformer(Class<T> resultClass) {
if ( resultClass == null ) { if ( resultClass == null ) {
throw new IllegalArgumentException( "resultClass cannot be null" ); throw new IllegalArgumentException( "resultClass cannot be null" );
} }
@ -55,13 +42,8 @@ public class AliasToBeanResultTransformer extends AliasedTupleSubsetResultTransf
} }
@Override @Override
public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) { public T transformTuple(Object[] tuple, String[] aliases) {
return false; T result;
}
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
Object result;
try { try {
if ( ! isInitialized ) { if ( ! isInitialized ) {
@ -121,16 +103,10 @@ public class AliasToBeanResultTransformer extends AliasedTupleSubsetResultTransf
return false; return false;
} }
AliasToBeanResultTransformer that = ( AliasToBeanResultTransformer ) o; AliasToBeanResultTransformer<?> that = (AliasToBeanResultTransformer<?>) o;
if ( ! resultClass.equals( that.resultClass ) ) { return resultClass.equals( that.resultClass )
return false; && Arrays.equals( aliases, that.aliases );
}
if ( ! Arrays.equals( aliases, that.aliases ) ) {
return false;
}
return true;
} }
@Override @Override

View File

@ -12,14 +12,11 @@ import org.hibernate.internal.util.collections.CollectionHelper;
/** /**
* {@link ResultTransformer} implementation which builds a map for each "row", * {@link ResultTransformer} implementation which builds a map for each "row",
* made up of each aliased value where the alias is the map key. * 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 Gavin King
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class AliasToEntityMapResultTransformer extends AliasedTupleSubsetResultTransformer { public class AliasToEntityMapResultTransformer implements ResultTransformer<Map<String,Object>> {
public static final AliasToEntityMapResultTransformer INSTANCE = new AliasToEntityMapResultTransformer(); public static final AliasToEntityMapResultTransformer INSTANCE = new AliasToEntityMapResultTransformer();
@ -30,8 +27,8 @@ public class AliasToEntityMapResultTransformer extends AliasedTupleSubsetResultT
} }
@Override @Override
public Object transformTuple(Object[] tuple, String[] aliases) { public Map<String,Object> transformTuple(Object[] tuple, String[] aliases) {
Map result = CollectionHelper.mapOfSize( tuple.length ); Map<String,Object> result = CollectionHelper.mapOfSize( tuple.length );
for ( int i = 0; i < tuple.length; i++ ) { for ( int i = 0; i < tuple.length; i++ ) {
String alias = aliases[i]; String alias = aliases[i];
if ( alias != null ) { if ( alias != null ) {
@ -41,11 +38,6 @@ public class AliasToEntityMapResultTransformer extends AliasedTupleSubsetResultT
return result; return result;
} }
@Override
public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
return false;
}
/** /**
* Serialization hook for ensuring singleton uniqueing. * 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; package org.hibernate.transform;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
import org.hibernate.query.Query; import org.hibernate.query.Query;
import org.hibernate.query.ResultListTransformer; import org.hibernate.query.ResultListTransformer;
@ -20,11 +21,13 @@ import org.hibernate.query.TupleTransformer;
* *
* @author Gavin King * @author Gavin King
* *
* @deprecated ResultTransformer is no longer supported. It has been split * @deprecated Use {@link TupleTransformer} and/or {@link ResultListTransformer}
* into {@link TupleTransformer} and {@link ResultListTransformer} to define
* functional interfaces.
*/ */
@Deprecated @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; package org.hibernate.transform;
import java.util.Arrays; 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(); public static final ToListResultTransformer INSTANCE = new ToListResultTransformer();
/** /**
@ -21,7 +22,7 @@ public class ToListResultTransformer extends BasicTransformerAdapter {
} }
@Override @Override
public Object transformTuple(Object[] tuple, String[] aliases) { public List<Object> transformTuple(Object[] tuple, String[] aliases) {
return Arrays.asList( tuple ); return Arrays.asList( tuple );
} }

View File

@ -26,8 +26,8 @@ final public class Transformers {
* Creates a ResultTransformer that will inject aliased values into * Creates a ResultTransformer that will inject aliased values into
* instances of Class via property methods or fields. * instances of Class via property methods or fields.
*/ */
public static ResultTransformer aliasToBean(Class target) { public static <T> ResultTransformer<T> aliasToBean(Class<T> target) {
return new AliasToBeanResultTransformer(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.cfg.AvailableSettings;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.query.Query; import org.hibernate.query.Query;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.testing.DialectChecks; import org.hibernate.testing.DialectChecks;
import org.hibernate.testing.RequiresDialectFeature; import org.hibernate.testing.RequiresDialectFeature;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.hibernate.transform.ResultTransformer;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -808,14 +808,18 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase {
criteria.where( criteriaBuilder.equal( root.get( "id" ), testData.prod1Id ) ); criteria.where( criteriaBuilder.equal( root.get( "id" ), testData.prod1Id ) );
Product prod = session.createQuery( criteria ) 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(); .uniqueResult();
// Product prod = ( Product ) session.createCriteria( Product.class )
// .setResultTransformer( DistinctRootEntityResultTransformer.INSTANCE )
// .add( Restrictions.eq( "id", testData.prod1Id ) )
// .uniqueResult();
assertNotNull( prod ); assertNotNull( prod );
assertEquals( "Incorrect Product.categories count for filter", 1, prod.getCategories().size() ); 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.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelection; import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.stat.QueryStatistics; import org.hibernate.stat.QueryStatistics;
import org.hibernate.transform.DistinctRootEntityResultTransformer; import org.hibernate.transform.ResultTransformer;
import org.hibernate.transform.Transformers; import org.hibernate.transform.Transformers;
import org.hibernate.testing.DialectChecks; import org.hibernate.testing.DialectChecks;
@ -3572,7 +3572,12 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
t = session.beginTransaction(); t = session.beginTransaction();
results = session.createQuery( "select a from Animal a, Animal b order by a.id" ) 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(); .list();
assertEquals( "Incorrect result size", 2, results.size()); assertEquals( "Incorrect result size", 2, results.size());
assertTrue( "Incorrect return type", results.get( 0 ) instanceof Animal ); assertTrue( "Incorrect return type", results.get( 0 ) instanceof Animal );

View File

@ -7,6 +7,7 @@
package org.hibernate.orm.test.hqlfetchscroll; package org.hibernate.orm.test.hqlfetchscroll;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@ -14,12 +15,12 @@ import java.util.Set;
import org.hibernate.Hibernate; import org.hibernate.Hibernate;
import org.hibernate.ScrollableResults; import org.hibernate.ScrollableResults;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.transform.ResultTransformer;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -43,7 +44,16 @@ public class HQLScrollFetchTest {
scope.inTransaction( scope.inTransaction(
session -> { session -> {
List list = session.createQuery( QUERY ) 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(); .list();
assertResultFromAllUsers( 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.ArrayList;
import java.util.List; import java.util.List;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinColumn;
@ -17,9 +17,9 @@ import jakarta.persistence.OneToMany;
import jakarta.persistence.Table; import jakarta.persistence.Table;
import org.hibernate.boot.MetadataSources; import org.hibernate.boot.MetadataSources;
import org.hibernate.transform.DistinctRootEntityResultTransformer;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.hibernate.transform.ResultTransformer;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -47,7 +47,12 @@ public class QueryExecutionTest extends BaseNonConfigCoreFunctionalTestCase {
assertThat( distinctResult.size(), CoreMatchers.is( 1 ) ); assertThat( distinctResult.size(), CoreMatchers.is( 1 ) );
final List distinctViaTransformerResult = session.createQuery( "select c from Customer c join fetch c.orders" ) 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 ) ); 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 only the PartnerA object from the query
return arg0[1]; return arg0[1];
} }
@SuppressWarnings("unchecked")
public List transformList(List arg0)
{
return arg0;
}
}); });
ScrollableResults sr = q.scroll(); ScrollableResults sr = q.scroll();
// HANA supports only ResultSet.TYPE_FORWARD_ONLY and // HANA supports only ResultSet.TYPE_FORWARD_ONLY and

View File

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