quarta-feira, 29 de setembro de 2010

ResultTransformer Inteligente =)

Pessoal .. estou passando aki p vcs um result transformer inteligente ! ....


 /**  
  *   
  * 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);  
 }  

2 comentários:

  1. Cara isso é realmente o que eu precisava para melhorar a performasse da aplicação no qual eu estou trabalhando.
    Mas não ficou claro a parte onde trata que tem que implementar um interface "ResultClass", poderia esclarecer?

    ResponderExcluir
    Respostas
    1. Sei que faz muito tempo q vc perguntou, mas mesmo assim estou respondendo agora hahahuahuha .. esta ali no codigo o result class

      Espero que tenha te ajudado

      Abs.

      Excluir