/**
*
* Result transformer inteligente
*
* @author Sergio , Alterado por Caio Rodrigo Paulucci
*
* @see AliasToBeanResultTransformer
*
*
*
*
*
* Similar ao AliasToBeanResultTransformer poróm ele aceita o uso de
* "nestedProperties" (aquela que vocó usa na JSTL ou EL)
*
* no criteria e pode instanciar mais de um tipo de classe.
*
* Inclusive uma parte do código foi copiado da classe original.
*
* <br />
*
* <b>1ó Forma de utilização</b>
*
* caso mais comum criar uma lista de objetos do mesmo tipo
* (HistoricoRegistroVO)
*
* <br />
*
* <code>
Criteria crit= createCriteria(HistoricoRegistroVO.class);
criteria.add(Restrictions.eq("this.registroVO.id", idDemanda));
ProjectionList projectionList = Projections.projectionList();
//seleciono somente os campos que me interessam, na estrutura real dos objetos (sem a necessidade de criação dos DTOs)
projectionList.add(Projections.property("this.ativo"), "ativo");
projectionList.add(Projections.property("this.descricao"), "descricao");
projectionList.add(Projections.property("this.encaminhamentoInterno"), "encaminhamentoInterno");
criteria.createAlias("this.usuarioVO", "usr");
criteria.createAlias("usr.unidadeVO", "unr");
projectionList.add(Projections.property("usr.login"), "usuarioVO.login");
projectionList.add(Projections.property("usr.nome"), "usuarioVO.nome");
projectionList.add(Projections.property("usr.id"), "usuarioVO.id");
projectionList.add(Projections.property("unr.descricao"), "usuarioVO.unidadeVO.descricao");
projectionList.add(Projections.property("this.dataUltimoMovimento"), "dataUltimoMovimento");
criteria.setProjection(projectionList);
//transformo o resultado no objeto passado e somente as propriedades e objetos que selecionei estóo preenchidas
criteria.setResultTransformer(new InteligentResultTransformer(HistoricoRegistroVO.class));
List resultado = criteria);
</code>
*
*
*
*
*
* <b>2ó Forma de utilização</b>
*
* Criar uma lista de objetos com um tipo definido pelo usuório
* (programmer)
*
* <code>
//Considerando que temos uma classe RegistroDenunciaReclamacaoVO que ó filho do RegistroVO
//preciso instónciar a classe correta de acordo com uma determinada condição
Criteria crit= createCriteria(RegistroVO.class);
criteria.createAlias("this.tipoRegistroVO", "tir");
criteria.createAlias("this.instituicaoFinanceiraVO", "ifr", Criteria.LEFT_JOIN);
ProjectionList projectionList = Projections.projectionList();
//seleciono os campos que me interessam
projectionList.add(Projections.property("this.enderecoVO"), "enderecoVO");
projectionList.add(Projections.property("ifr.nomeFantasia"), "instituicaoFinanceiraVO.nomeFantasia");
projectionList.add(Projections.property("tir.descricao"), "tipoRegistroVO.descricao");
projectionList.add(Projections.property("tir.id"), "tipoRegistroVO.id");
projectionList.add(Projections.property("tir.comportamentoTipoRegistroVO"), "tipoRegistroVO.comportamentoTipoRegistroVO");
projectionList.add(Projections.property("this.id"), "id");
projectionList.add(Projections.property("this.idCrm"), "idCrm");
projectionList.add(Projections.property("this.idConsulta"), "idConsulta");
//esses dois campos pertencem a classe RegistroDenunciaReclamacaoVO somente
projectionList.add(Projections.property("this.dataRanking"), "dataRanking");
projectionList.add(Projections.property("this.rankingCarimbo"), "rankingCarimbo");
criteria.setProjection(projectionList);
//ao invós de passar a classe como no exemplo anterior
//eu passo uma classe que implementa a interface ResultClass
InteligentResultTransformer rt = new InteligentResultTransformer(new ResultClass(){
//aqui eu recebo um Map onde tenho como chave os alias adicionados no projectionList
//e como valores os resultados retornados pela consulta
public Class getResultClass(Map resultMap) {
//faóo uma comparação e retorno o tipo da classe que quero criar a instóncia para essa linha
ComportamentoTipoRegistroVO comportamento = (ComportamentoTipoRegistroVO) resultMap.get("tipoRegistroVO.comportamentoTipoRegistroVO");
if(DadosConstantes.COMPORTAMENTO_INFORMACAO.equals(comportamento.getId())){
return RegistroVO.class;
}
if(DadosConstantes.COMPORTAMENTO_IRREGULARIDADE.equals(comportamento.getId())){
return RegistroDenunciaReclamacaoVO.class;
}
return null;
}
});
criteria.setResultTransformer(rt);
criteria);
</code>
*
*
*
*
*
*
*/
public class InteligentResultTransformer implements ResultTransformer {
private static final long serialVersionUID = -7124932916590109519L;
/**
*
* Classe de resultado (se o tipo da classe for fixo)
*/
private Class resultClass;
/**
*
* objeto para acessar as propriedades de um tipo de classe
*/
private PropertyAccessor propertyAccessor;
/**
*
* Implemntaóao que deveró fornecer java.lang.Class a ser instónciado para a
* linha atual do registro
*/
private ResultClass rc;
/**
*
* Cache de propertyAccessor, para evitar de ficar instónciando esse fiduma
* toda hora.
*
* Se nóo fosse pesado instanciar ele o hibernate nóo usaria uma varióvel de
* instóncia
*
* para guardar ele
*/
private HashMap propertyAccessors = new HashMap();
/**
*
* Tupla de registros retornados pela consulta
*/
private Object[] tuple;
/**
*
* Alias adicionados no Projections.projectionList()
*/
private String[] aliases;
/**
*
* Tipo dinamico para a coleção a ser criada
*
* @param rc
*/
public InteligentResultTransformer(ResultClass rc) {
this.rc = rc;
}
/**
*
* A coleção a ser criada seró de um tipo somente
*
*
*
* @param resultClass
*/
public InteligentResultTransformer(Class resultClass) {
if (resultClass == null)
throw new IllegalArgumentException("resultClass cannot be null");
this.resultClass = resultClass;
}
/*
*
* (non-Javadoc)
*
* @see
* org.hibernate.transform.ResultTransformer#transformTuple(java.lang.Object
* [], java.lang.String[])
*/
public Object transformTuple(Object[] tuple, String[] aliases) {
this.tuple = tuple;
this.aliases = aliases;
Object result;
try {
// instancia a classe de resultado
result = getResultClass().newInstance();
for (int i = 0; i < aliases.length; i++) {
String alias = aliases[i];
if (alias != null) {
if (tuple[i] == null) {
continue;
}
/*
* se o alias contóm ponto ó porque a propriedade a ser
* setada deveró ser
*
* navegada ató o final para ser preenchida
*
* (Ex: registroVO.tipoRegistroVO.descricao
*
* - instancia uma vez o tipoRegistroVO
*
* - seta a descricao com o valor da tupla)
*/
if (alias.indexOf(".") != -1) {
String[] split = alias.split("\\.");
Object resultado = result;
for (int j = 0; j < split.length; j++) {
String property = split[j];
// se for a óltima propriedade o valor da tupla
// deveró ser setado nela
if (j == (split.length - 1)) {
PropertyUtils.setProperty(resultado, property,
tuple[i]);
break;
}
// do contrório instancio o tipo da propriedade se
// necessório e passo para o próximo
Object valor = PropertyUtils.getProperty(resultado,
property);
if (valor == null) {
Class tipo = PropertyUtils.getPropertyType(
resultado, property);
valor = tipo.newInstance();
PropertyUtils.setProperty(resultado, property,
valor);
}
resultado = valor;
}
} else {
// se estiver em modo inteligente
if (this.isInInteligentMode()) {
// pode ser que a propriedade nóo exista na classe
// que foi retornada pelo ResultClass
if (PropertyUtils.isWriteable(result, alias)) {
Setter mainSetter = getPropertyAcessor()
.getSetter(getResultClass(), alias);
mainSetter.set(result, tuple[i], null);
}
} else {
// do contrório nóo ó admissóvel que a propriedade
// nóo exista na classe informada
Setter mainSetter = getPropertyAcessor().getSetter(
getResultClass(), alias);
mainSetter.set(result, tuple[i], null);
}
}
}
}
} catch (Exception e) {
throw new HibernateException(e);
}
return result;
}
/**
*
* Retornar a classe que deveró ser instanciada e preenchida com o resultado
*
* @return
*/
private Class getResultClass() {
// se o rc ó nulo nóo estó em modo inteligente
if (!this.isInInteligentMode()) {
return this.resultClass;
}
// recupero um mapa com o resultado cró retornado pelo hibernate
Map propriedades = getMap(tuple, aliases);
// invoco o result class que foi passado com as propridades
Class resultClass2 = rc.getResultClass(propriedades);
// e ele deveró me passar o tipo da classe a ser instanciada
return resultClass2;
}
/**
*
* Cria um mapa de propriedades para passar para a instóncia da ResultClass
*
* @param tuple
*
* @param aliases
*
* @return
*/
private Map getMap(Object[] tuple, String[] aliases) {
HashMap map = new HashMap();
for (int i = 0; i < aliases.length; i++) {
map.put(aliases[i], tuple[i]);
}
return map;
}
/*
*
* (non-Javadoc)
*
* @see
* org.hibernate.transform.ResultTransformer#transformList(java.util.List)
*/
public List transformList(List collection) {
return collection;
}
/**
*
* Retorna o property acessor de acordo com a classe que seró instónciada
*
* @return
*/
public PropertyAccessor getPropertyAcessor() {
if (propertyAccessor == null && !this.isInInteligentMode()) {
propertyAccessor = new ChainedPropertyAccessor(
new PropertyAccessor[] {
PropertyAccessorFactory.getPropertyAccessor(
resultClass, null),
PropertyAccessorFactory
.getPropertyAccessor("field") });
}
if (this.isInInteligentMode()) {
Class resultClass2 = this.getResultClass();
String className = resultClass2.getName();
Object propertyAcessor = this.propertyAccessors.get(className);
if (propertyAcessor == null) {
this.propertyAccessors.put(
className,
new ChainedPropertyAccessor(new PropertyAccessor[] {
PropertyAccessorFactory.getPropertyAccessor(
resultClass2, null),
PropertyAccessorFactory
.getPropertyAccessor("field") }));
}
return (PropertyAccessor) this.propertyAccessors.get(className);
}
return this.propertyAccessor;
}
/**
*
*
*
* @param resultClass
*/
public void setResultClass(ResultClass resultClass) {
this.rc = resultClass;
}
/**
*
* Quando o {@link InteligentResultTransformer} ó instanciado para criar um
* tipo de objeto
*
* Esse mótodo retorna false.
*
* Quando essa classe ó instanciada com uma instancia do ResultClass
*
* Ele retorna true.
*
* @return
*/
private boolean isInInteligentMode() {
return this.rc != null;
}
}
e o ResultClass :
import java.util.Map;
/**
*
* Classe de resultado, deveró retornar o tipo do objeto para ser instanciado
* de acordo com o resultMap passado como parómetro
*
* @see InteligentResultTransformer
* @author deinf.sdantas
*
*/
public interface ResultClass {
public Class getResultClass(Map resultMap);
}
Cara isso é realmente o que eu precisava para melhorar a performasse da aplicação no qual eu estou trabalhando.
ResponderExcluirMas não ficou claro a parte onde trata que tem que implementar um interface "ResultClass", poderia esclarecer?
Sei que faz muito tempo q vc perguntou, mas mesmo assim estou respondendo agora hahahuahuha .. esta ali no codigo o result class
ExcluirEspero que tenha te ajudado
Abs.