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:
parent
22457cc74d
commit
c43b6ff606
|
@ -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 ) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -32,6 +32,6 @@ public class RowTransformerTupleTransformerAdapter<T> implements RowTransformer<
|
|||
|
||||
@Override
|
||||
public int determineNumberOfResultElements(int rawElementCount) {
|
||||
return tupleTransformer.determineNumberOfResultElements( rawElementCount );
|
||||
return rawElementCount;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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() );
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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 ) );
|
||||
}
|
||||
);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
Loading…
Reference in New Issue