Created
April 6, 2020 08:18
-
-
Save fabio-boldrini/1bb3bdeb563fbec20ed481e1e458c29d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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