RSS

Paginação por Demanda com JSF – Parte 3

28 dez

Note que os métodos são genéricos, mas que isso só funcionária se a query nunca tivesse nenhum tipo de restrição, ou seja, se você quisesse realizar o count apenas de determinadas informações, dessa maneira seria impossível e você teria que reescrever o método count sempre que precisasse restringir alguma informação.
Pensando nisso vamos abstrair mais ainda o Método count. Nele agora será necessário informar às restrições que deverão compor a query.
Vejamos como ficará o método count.

public Integer count(List<Criterion> restricoes){
Integer size = 0;
try {
getHibernate().beginTransaction();
Criteria criteria = getHibernate().getSession().createCriteria(getEntidade().getClass());
if(restricoes != null){
for (Criterion criterion : restricoes) {
criteria.add(criterion);
}
}
criteria.setProjection(Projections.rowCount());
size = (Integer) criteria.uniqueResult();
getHibernate().commit();
} catch (Exception e) {
getHibernate().rollback();
e.printStackTrace();
} finally {
getHibernate().close();
}
return size;
}

Note que agora é solicitado uma Lista de restrições (Criterions) que serão utilizados pela criteria. Isso torna o método genérico a qualquer consulta, sendo necessário passar a restrição que desejar dentro de uma lista, da seguinte maneira.


List lista = new ArrayList();
lista.add(Restrictions.eq("usuario", usuario.GetUsuario()));

Dessa maneira é informado qual restrição quero para o método count.
Pensando dessa forma o método listByCriteriaDemanda deverá permitir restrições, ordenações e até mesmo projeções. Aqui entramos em um problema:
Teremos que prevenir o LIE (Lazy Initialization Exception). Se a sua entidade possuir uma listagem e está será utilizada na tela, a mesma deverá ser Lazy false ou você terá que realizar a prevenção do LIE. No meu caso teremos que inicializar essa dependência.

Mas como? Meu DAO é genérico, não tenho acesso aos atributos da classe e não sei se esta classe possui ou não listagens que poderão causar o LIE.
Vamos utilizar um recurso do Java. Vamos utilizar reflexão, ou seja, vamos descobrir se a classe possui ou não atributos que são listas e iremos inicializar esses atributos.

Vamos ver como ficaria o nosso método após a adição das restrições e inicialização de objetos de um determinado tipo por reflexão.

public List<T> listByCriteriaDemanda
(Integer startPage, Integer maxPage, List<Criterion> restricoes, List<Projection> projecoes, List<Order> ordenacao){

         List<T> list = new ArrayList<T>();

         try {

                   getHibernate().beginTransaction();

                   Criteria criteria = getHibernate().getSession().createCriteria(getEntidade().
getClass());

if(restricoes !=null){

for(Criterion r: restricoes){

criteria.add(r);

}

}

if(projecoes != null){

for (Projection p : projecoes) {

criteria.setProjection(p);

}

}

if(ordenacao != null){

for(Order order: ordenacao){

criteria.addOrder(order);

}

}

criteria.setFirstResult(startPage);

criteria.setMaxResults(maxPage);

list = criteria.list();

for (T t : list) {

for (Method method : t.getClass().getMethods()) {

if(method.getName().indexOf(“get”) > -1){

Object obj = method.invoke(t);

if(obj instanceof java.util.Collection){

for (T lista: (List<T>)obj) {

Hibernate.initialize(lista);

}

}

}

}

}

getHibernate().commit();

} catch (Exception e) {

getHibernate().rollback();

e.printStackTrace();

} finally {

getHibernate.close();

}

return list;

}

Nosso método agora ficou bastante genérico, trouxemos as restrições, as projeções e as ordenações para dentro dele. Na nossa classe agora poderemos criar nossas restrições, projeções e ordenação e manter nosso DAO genérico, sem precisar implementar novamente as funcionalidades da classe.

O trecho abaixo é referente a parte de reflexão que iremos utilizar para descobrir se um atributo é uma coleção ou não, para podermos inicializar este atributo.

for (T t : list) {

 for (Method method : t.getClass().getMethods()) {

if(method.getName().indexOf(“get”) > -1){

Object obj = method.invoke(t);

if(obj instanceof java.util.Collection){

for (T lista: (List<T>)obj) {

Hibernate.initialize(lista);

}

}

}

}

}

Aqui nos fazemos uma iteração na lista criada pela criteria. Criamos um objeto do tipo Method, esse objeto é um Array e é carregado a partir do método

t.getClass.getMethods();

Esse método retorna um Methods[].

Feito isso nós testamos se no nome do método existe a palavra “get”, pois será necessário invocar esse get para sabermos qual o tipo de objeto será retornado.
O método indexOf retorna >-1 caso seja verdadeiro, ou seja, se a palavra get existir no nome do método então o retorno será verdadeiro.
Com isso nós invocamos o método através do method.invoke(t);
Como não sabemos qual o tipo de retorno então criamos um objeto do tipo Object que irá receber o retorno. Se esse objeto for filho de collection (List, Set, ArrayList, HashTree, etc) então iremos iterar sobre esse objeto e iremos inicializar item após item da listagem resultante. Por padrão, os relacionamentos OneToMany retornam um objeto do tipo PersistenceBag que é filho de Collection.

Feito isso sua classe está completamente inicializada e não haverá problemas com LazyInitialization e você terá uma paginação em demanda funcional.

Em breve estarei disponibilizando um projeto war contendo esse DAO, SuperDAO e as classes necessárias para realizar a paginação. Um exemplo funcional com acesso a uma base de dados.

 
1 Comment

Publicado por em dezembro 28, 2008 em Dicas, JSF

 

Uma resposta para Paginação por Demanda com JSF – Parte 3

  1. Haylson Martins

    novembro 5, 2010 at 5:53 am

    Poxa… muito legal sua abordagem sobre paginação sob demanda… estou tentando implementar em um projeto próprio seguindo seus passos… mas estou com algumas dificuldades com as classes genéricas. Voce disponibilizou o projeto .war com o exemplo funcional? Não achei por aqui… se fosse possível me encaminhar agradeceria…

    Parabens pelo post Marcus…

    Forte Abraço.

    Haylson Martins

     

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Sair / Alterar )

Imagem do Twitter

You are commenting using your Twitter account. Sair / Alterar )

Foto do Facebook

You are commenting using your Facebook account. Sair / Alterar )

Connecting to %s

 
Seguir

Obtenha todo post novo entregue na sua caixa de entrada.