Como usar "FetchType.LAZY" acessando serviços REST stateless ?

370 views
Skip to first unread message

Hugo Castro Araujo

unread,
Apr 10, 2015, 11:22:50 AM4/10/15
to ce...@googlegroups.com
Caros,

Estou precisando utilizar o "LAZY loading" para não retornar os dados de atributos mapeados como @OneToMany ou @ManyToMany, uma vez que estes serão acessados (se acessados) mediante requisição ajax, uma espécie de autocomplete e/ou lookup. Adicionalmente, quero que manter meus serviços REST como stateless, ou seja, não quero criar sessões no servidor web que irá fornecer tais serviços (que no caso é o Wildfly com RESTeasy).

Porém, ao fazê-lo, me deparo como o erro abaixo:

org.jboss.resteasy.spi.UnhandledException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: br.com.absonline.model.Associado.dependentes, could not initialize proxy - no Session


Já procurei no google, mais achei muito confuso. Se alguém já passou por isso e puder dar uma dica...


Valeu, e abraço a todos....

Daniel Cunha

unread,
Apr 10, 2015, 11:23:41 AM4/10/15
to CEJUG
Hugo,

http://uaihebert.com/quatro-solucoes-para-lazyinitializationexception/
> --
> -- Você está inscrito na lista de discussão técnica do CEJUG. Para sair da
> lista de discussão, envie um email para cejug+un...@googlegroups.com.
> ---
> Você recebeu essa mensagem porque está inscrito no grupo "CEJUG" dos Grupos
> do Google.
> Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie
> um e-mail para cejug+un...@googlegroups.com.
> Para postar nesse grupo, envie um e-mail para ce...@googlegroups.com.
> Acesse esse grupo em http://groups.google.com/group/cejug.
> Para mais opções, acesse https://groups.google.com/d/optout.



--
Best regard,
Daniel Cunha (soro)

Paulo Jr.

unread,
Apr 10, 2015, 12:00:22 PM4/10/15
to CEJUG
Não sei se a solução do Daniel resolveu seu problema, mas considero isso mais uma questão conceitual que de tecnologia.

Uma vez que você tem serviços REST, é impossível ter o EntityManager aberto na view. O que você vai precisar fazer é definir muito bem o que seus serviços REST irão retornar e já realizar o carregamento deles no servidor para que o JSON retornado esteja com tudo que for preciso.

Lembre-se que OpenEntityManagerInView só funciona com JSP/XHTML/etc quando é processado no servidor. Uma vez que já está no cliente, o servidor já emitiu o response e não deve existir mesmo mais sessions/entitymanager aberto.

O que o RestEasy deve fazer (chutando, pois não fui a fundo nele) é tentar carregar os relacionamentos no servidor. Que é a mesma coisa que o Jackson faz quando usamos Spring, eu imagino. Assim, ele tenta puxar os relacionamentos antes de gerar o json. Aí sim o OEMIV pode funcionar, mas em se tratando de serviços, prefira sempre deixar bem definido qual será o retorno dos seus serviços do que deixar que o framework exponha todos os relacionamento.

Espero que tenha dado para entender :D

Abraço

Você está recebendo esta mensagem porque se inscreveu no grupo "CEJUG" dos Grupos do Google.

Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para cejug+un...@googlegroups.com.
Para postar neste grupo, envie um e-mail para ce...@googlegroups.com.
Visite este grupo em http://groups.google.com/group/cejug.
Para obter mais opções, acesse https://groups.google.com/d/optout.



--
Paulo Alves Junior
Twitter: @paulojribp
Github: http://github.com/paulojribp
Instrutor - Caelum | Ensino e Inovação
Hurraa - OpenSource project to resource management

Rafael Ponte

unread,
Apr 10, 2015, 12:51:45 PM4/10/15
to ce...@googlegroups.com
Olá Hugo,

Embora você trabalhe com serviços REST, nós podemos considerar o tipo de retorno (JSON, XML etc) como sua view, de tal forma que o padrão OSIV poderia ajudar a evitar os LIE. No entanto, como mencionado pelo Paulo, seria melhor você criar consultas planejadas com o Hibernate (JPQL, NamedQuerys ou Criteria), assim você carregaria somente os dados necessários para gerar seu JSON.

Um abraço!

Rafael Ponte
TriadWorks | Formação Java
http://cursos.triadworks.com.br

Hugo Castro Araujo

unread,
Apr 10, 2015, 12:58:06 PM4/10/15
to ce...@googlegroups.com
Caros,

Valeu pelas respostas. 

Li o artigo sugerido pelo Daniel e acredito que uma das quatro soluções descritas no artigo está indo ao encontro do que você disse na frase "prefira sempre deixar bem definido qual será o retorno dos seus serviços do que deixar que o framework exponha todos os relacionamento"

Escolher quais atributos do meu bean devem ser marcados EAGER por Default (tais como pequenas listas, ou, mesmo atributos @OneToOne que por padrão já são EAGER), e, utilizar "Join Query" para fazer o fetch de atributos LAZY quando necessários.

Como minha aplicação mantém a sessão no browser, não preciso de uma sessão web ou mesmo de um bean statefull.

No entanto, conforme esse link JPA Criteria API by samples – Part-II posso utilizar o "fetch join query" de 3 formas:

1) Por HSQL (que foi também o exemplo do artigo sugerido pelo Daniel);
2) Por CriteriaQuery, chamando o método "fetch" e passando o atributo que deseja buscar; e
3) Por TypedQuery.

Ainda não testei usando o HSQL, porém o meu "findAll" (da classe AbstractBean) está implementado usando o CriteriaQuery, porém seu uso do "fetch", conforme abaixo:

     CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        return getEntityManager().createQuery(cq).getResultList();


Acho estranho ele dar o erro, e acredito que se trocar por HSQL o erro irá continuar. Andei lendo que o Hibernate (implementação do JPA no Wildfly) utiliza o conceito de Proxy e que por mais que o atributo esteja anotado como LAZY, o Hibernate irá forçar que todos os atributos seja EAGER.


P.S: Estou tentando corrigir com base no HSQL, obrigado.

Paulo Jr.

unread,
Apr 10, 2015, 1:10:49 PM4/10/15
to CEJUG
Hugo,

Acho estranho ele dar o erro, e acredito que se trocar por HSQL o erro irá continuar. Andei lendo que o Hibernate (implementação do JPA no Wildfly) utiliza o conceito de Proxy e que por mais que o atributo esteja anotado como LAZY, o Hibernate irá forçar que todos os atributos seja EAGER.
Isso é estranho, não faz muito sentido. Na verdade é o padrão do JPA e que o Hibernate respeita é, se termina com Many é lazy (@OneToMany, @ManyToMany) se termina com One é EARGER (@OneToOne, @ManyToOne). Porém, se você especificar o fetch desses caras, o JPA/Hiberante irá respeitar sua configuração.

Escolher quais atributos do meu bean devem ser marcados EAGER por Default (tais como pequenas listas, ou, mesmo atributos @OneToOne que por padrão já são EAGER), e, utilizar "Join Query" para fazer o fetch de atributos LAZY quando necessários.
Muito cuidado com o que vai escolher para ser EAGER. Realmente listas de domínio muito pequenas, com tamanho pré definido e que não tenha a menor chance de crescer, e se no futuro crescer mudar para LAZY.

1) Por HSQL (que foi também o exemplo do artigo sugerido pelo Daniel);
2) Por CriteriaQuery, chamando o método "fetch" e passando o atributo que deseja buscar; e
3) Por TypedQuery.
TypedQuery nada mais é que uma Query tipada, evitando casting e aquelas chatices de warnings do eclipse. A sua consulta que rodará na TypedQuery é que usará o fetch. O que considero a forma mais fácil. Usar Criteria só para isso, não vejo necessidade.

Assim, o jeito mais simples é "select o from Objeto o fetch join OutroObjeto oo". Assim, o JPA já vai trazer seu outro objeto e você saberá o que foi retornado.

Agora, lebre-se que o RestEasy vai tentar carregar os relacionamento pois ele faz get's para montar o JSON, então os relacionamento que você não quer trazer, terá que setar para nulo.

Li o artigo sugerido pelo Daniel e acredito que uma das quatro soluções descritas no artigo está indo ao encontro do que você disse na frase "prefira sempre deixar bem definido qual será o retorno dos seus serviços do que deixar que o framework exponha todos os relacionamento"
Eu não abri o artigo, mas chutaria que ele está falando para carregar os relacionamento em uma JSP, que é diferente de usar um serviço. JSP não fica exposta para fora da sua aplicação, em tese, seus serviços REST sim.

Veja se isso ajudar em algo.

Abraço,


Hugo Castro Araujo

unread,
Apr 10, 2015, 2:54:59 PM4/10/15
to ce...@googlegroups.com
Caros,

Obrigado a todos pelas respostas.

Quando você disse...

Eu não abri o artigo, mas chutaria que ele está falando para carregar os relacionamento em uma JSP, que é diferente de usar um serviço. JSP não fica exposta para fora da sua aplicação, em tese, seus serviços REST sim.

Então resolvi isolar o código para exibir os dados no console (System.out). Então pude perceber que o problema não estava relacionado à camada de visão, e, sim a forma como o serviço REST serializava os meus Bean resultante. Ao criar o Json, o atributo marcado como LAZY era acessado, o que gerava o erro. Assim, seguindo a orientação do link abaixo e um pouquinho d reflection, pude serializar o Json descartando atributos marcados (via anotação) como LAZY.



Obrigado a todos pela ajuda!

Paulo Jr.

unread,
Apr 10, 2015, 3:27:09 PM4/10/15
to CEJUG
Bacana, feliz em ajudar Hugo.

Abraço,
Reply all
Reply to author
Forward
0 new messages