Skip to content

Instantly share code, notes, and snippets.

@fabio-boldrini
Created April 6, 2020 08:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fabio-boldrini/1bb3bdeb563fbec20ed481e1e458c29d to your computer and use it in GitHub Desktop.
Save fabio-boldrini/1bb3bdeb563fbec20ed481e1e458c29d to your computer and use it in GitHub Desktop.
/*
* 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 it.netservice.cms.hibernate;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.hibernate.HibernateException;
import org.hibernate.property.access.internal.PropertyAccessStrategyBasicImpl;
import org.hibernate.property.access.internal.PropertyAccessStrategyChainedImpl;
import org.hibernate.property.access.internal.PropertyAccessStrategyFieldImpl;
import org.hibernate.property.access.internal.PropertyAccessStrategyMapImpl;
import org.hibernate.property.access.spi.Setter;
import org.hibernate.transform.AliasedTupleSubsetResultTransformer;
/**
* 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>
*
*/
public class CmsAliasToBeanResultTransformer extends AliasedTupleSubsetResultTransformer {
// IMPL NOTE : due to the delayed population of setters (setters cached
// for performance), we really cannot properly define equality for
// this transformer
private static final long serialVersionUID = 1L;
private final Class<?> resultClass;
private boolean isInitialized;
private String[] aliases;
private Setter[] setters;
public static class CmsTransformer<T extends Object, R extends Object> {
private Function<T, R> t;
public CmsTransformer(Class<T> input, Class<R> output, Function<T, R> t) {
this.t = t;
}
@SuppressWarnings("unchecked")
public R transform(Object input) {
return t.apply((T)input);
}
}
private final Map<String, CmsTransformer<? extends Object, ? extends Object>> mapTransformer;
private List<String> aliasList;
public CmsAliasToBeanResultTransformer(Class<?> resultClass, Map<String, CmsTransformer<? extends Object, ? extends Object>> mapTransformer) {
this(resultClass, mapTransformer, null);
}
public CmsAliasToBeanResultTransformer(Class<?> resultClass, Map<String, CmsTransformer<? extends Object, ? extends Object>> mapTransformer, List<String> aliasList) {
if (resultClass == null) {
throw new IllegalArgumentException("resultClass cannot be null");
}
isInitialized = false;
this.resultClass = resultClass;
this.mapTransformer = mapTransformer;
this.aliasList = aliasList;
}
@Override
public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
return false;
}
@Override
public Object transformTuple(Object[] tuple, String[] _aliases) {
Object result;
String[] aliases;
if (this.aliasList == null) {
aliases = _aliases;
} else {
aliases = (String[]) aliasList.toArray(new String[aliasList.size()]);
}
try {
if (!isInitialized) {
initialize(aliases);
} else {
check(aliases);
}
result = resultClass.newInstance();
for (int i = 0; i < aliases.length; i++) {
Setter setter = setters[i];
if (setter != null) {
// Class<?> setterType = setter.getMethod().getParameterTypes()[0];
Object el = tuple[i];
String alias = aliases[i];
if (mapTransformer.containsKey(alias)) {
CmsTransformer<? extends Object, ? extends Object> transformer = mapTransformer.get(alias);
Object transformerResult = transformer.transform(el);
setter.set(result, transformerResult, null);
} else {
setter.set(result, el, null);
}
}
}
} catch (InstantiationException e) {
throw new HibernateException("Could not instantiate resultclass: " + resultClass.getName());
} catch (IllegalAccessException e) {
throw new HibernateException("Could not instantiate resultclass: " + resultClass.getName());
}
return result;
}
private void initialize(String[] aliases) {
PropertyAccessStrategyChainedImpl propertyAccessStrategy = new PropertyAccessStrategyChainedImpl(
PropertyAccessStrategyBasicImpl.INSTANCE,
PropertyAccessStrategyFieldImpl.INSTANCE,
PropertyAccessStrategyMapImpl.INSTANCE);
this.aliases = new String[aliases.length];
setters = new Setter[aliases.length];
for (int i = 0; i < aliases.length; i++) {
String alias = aliases[i];
if (alias != null) {
this.aliases[i] = alias;
setters[i] = propertyAccessStrategy.buildPropertyAccess(resultClass, alias).getSetter();
}
}
isInitialized = true;
}
private void check(String[] aliases) {
if (!Arrays.equals(aliases, this.aliases)) {
throw new IllegalStateException(
"aliases are different from what is cached; aliases=" + Arrays.asList(aliases) +
" cached=" + Arrays.asList(this.aliases));
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
CmsAliasToBeanResultTransformer that = (CmsAliasToBeanResultTransformer) o;
if (!resultClass.equals(that.resultClass)) {
return false;
}
if (!Arrays.equals(aliases, that.aliases)) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = resultClass.hashCode();
result = 31 * result + (aliases != null ? Arrays.hashCode(aliases) : 0);
return result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment