VRaptor 3 + Hibernate + OpenSessionInViewFilter(Spring): LazyInitializationException[RESOLVIDO]

Pessoal,

Estou fazendo alguns testes com o vraptor, usando ele para fazer a parte view. Fazendo um jsp simples de filtro, onde lista somente dados dos clientes funcionou ok. Quando alterei para a cada registro de cliente mostrar também os dependentes obtive LazyInitializationException.

Obs. Eu tenho a parte de back-end toda pronta com Spring, pois pretendo fazer testes com outros frameworks.

clienteFiltrar.jsp

	<c:forEach items="${clienteList}" var="c">
		<tr>
			...
		</tr>
		<c:if test="${c.dependentes ne null and not empty c.dependentes}">
			<c:forEach items="${c.dependentes}" var="d">
				<tr>
					...
				</tr>
			</c:forEach>
		</c:if>
	</c:forEach>

ClienteController.java

@Resource
public class ClienteController {
	private ClienteService clienteService;
	public ClienteController(ClienteService clienteService) {
		this.clienteService = clienteService; 
	}
	public List<Cliente> clienteFiltrar(String nome, String telefone) {
		if (nome == null && telefone == null) {
			return null;
		}
		return clienteService.filtroLista(nome, telefone);
	}
}

Minhas classes de serviço e de acesso aos dados estão funcionando.

root cause

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: blah.Cliente.dependentes, no session or session was closed
	org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
	org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
	org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:119)
	org.hibernate.collection.PersistentSet.isEmpty(PersistentSet.java:169)
	org.apache.el.parser.AstEmpty.getValue(AstEmpty.java:53)
	org.apache.el.parser.AstNot.getValue(AstNot.java:42)
	org.apache.el.parser.AstAnd.getValue(AstAnd.java:42)
	org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:186)
	org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(PageContextImpl.java:935)
	org.apache.jsp.WEB_002dINF.jsp.cliente.clienteFiltrar_jsp._jspx_meth_c_005fif_005f1(clienteFiltrar_jsp.java:264)
	org.apache.jsp.WEB_002dINF.jsp.cliente.clienteFiltrar_jsp._jspx_meth_c_005fforEach_005f0(clienteFiltrar_jsp.java:211)
	org.apache.jsp.WEB_002dINF.jsp.cliente.clienteFiltrar_jsp._jspx_meth_c_005fif_005f0(clienteFiltrar_jsp.java:156)
	org.apache.jsp.WEB_002dINF.jsp.cliente.clienteFiltrar_jsp._jspService(clienteFiltrar_jsp.java:95)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:377)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:313)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:260)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	br.com.caelum.vraptor.core.DefaultStaticContentHandler.deferProcessingToContainer(DefaultStaticContentHandler.java:64)
	br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:80)

web.xml

	<context-param>
		<param-name>br.com.caelum.vraptor.provider</param-name>
		<param-value>br.com.caelum.vraptor.ioc.spring.SpringProvider</param-value>
	</context-param>

	<filter>
		<filter-name>vraptor</filter-name>
		<filter-class>br.com.caelum.vraptor.VRaptor</filter-class>
	</filter>
	
	<filter-mapping>
		<filter-name>vraptor</filter-name>
		<url-pattern>/*</url-pattern>
		<dispatcher>FORWARD</dispatcher>
		<dispatcher>REQUEST</dispatcher>
	</filter-mapping>	

	<filter>
		<filter-name>openSessionInViewFilter</filter-name>
		<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
		<init-param>  
			<param-name>sessionFactoryBeanName</param-name>  
			<param-value>annotationSessionFactory</param-value>  
		</init-param>  
	</filter>
	
	<filter-mapping>
		<filter-name>openSessionInViewFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

se eu inverter as posições dos filters, colocando openSessionInViewFilter antes do vraptor, o tomcat inicia, mas quando executo /cliente/clienteFiltrar ele reclama que não que não foi registrado o ContextLoadListener do Spring:

DEBUG [http-8026-1] (OpenSessionInViewFilter.java:239) - Using SessionFactory 'annotationSessionFactory' for OpenSessionInViewFilter
24/11/2010 15:22:33 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet default threw exception
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
	at org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(WebApplicationContextUtils.java:84)
	at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.lookupSessionFactory(OpenSessionInViewFilter.java:241)

Realmente ele não está lá porque, acredito eu, o VRaptor deveria ter registrado isso.

Se eu coloco o listener do spring, funciona, mas não sei se isso tem impacto e/ou problema.

Alguem tem alguma luz? Falta alguma coisa pra configurar?

Cara tenta o seguinte:
Precisa inicializar o que quer retornar lá no DAO usando: Hibernate.initialize("");

for (Classe obj : entityList) {
	Hibernate.initialize();
}

Quando você usa o Suporte ao hibernate pelo VRaptor, ele adiciona automaticamente o suporte ao open session in view.

a configuração

<context-param>  
    <param-name>br.com.caelum.vraptor.provider</param-name>  
    <param-value>br.com.caelum.vraptor.ioc.spring.SpringProvider</param-value>  
</context-param> 

não é necessária…

como vc está usando as sessões do hibernate? pelo spring (HibernateTemplate ou coisa do tipo)… o OpenSessionInViewFilter só funciona se vc controlar a sessão usando o Spring.

vc precisa também declarar o ContextLoaderListener pro OpenSessionInView funcionar:

<listener>
 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

@zoren,

o suporte do hibernate é feito pelo spring não pelo vraptor.

@Lucas
Vou testar e já posto aqui

Funcionou.

ok, retirada.

Exatamente. Estou usando HibernateTemplate mas não tinha o ContextLoadListener declarado no web.xml. Eu não sabia se haveria algum problema em ter ele junto com o provider do vraptor. Tirando o provider e adicionando o listener passou a funcionar.

Grato!

No meu caso não deu certo

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;

&lt;beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/tx 
	       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
           http://www.springframework.org/schema/task 
	       http://www.springframework.org/schema/task/spring-task-3.0.xsd
	       http://www.springframework.org/schema/aop 
	       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd"&gt;

	&lt;bean id="emf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"&gt;
		&lt;property name="persistenceUnitName" value="default" /&gt;
	&lt;/bean&gt;

	&lt;bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"&gt;
		&lt;property name="entityManagerFactory" ref="emf" /&gt;
	&lt;/bean&gt;

	&lt;tx:annotation-driven proxy-target-class="true" /&gt;

	&lt;task:annotation-driven /&gt;

	&lt;context:annotation-config /&gt;

	&lt;context:component-scan base-package="br.com.devcase.toolkit.service,sqdasa.service"/&gt;
	
	&lt;bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/&gt;
	
	&lt;bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/&gt;
	
&lt;/beans&gt;

E no meu web.xml

&lt;context-param&gt;
		&lt;param-name&gt;br.com.caelum.vraptor.encoding&lt;/param-name&gt;
		&lt;param-value&gt;UTF-8&lt;/param-value&gt;
	&lt;/context-param&gt;

	&lt;context-param&gt;
		&lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
		&lt;param-value&gt;classpath:applicationContext.xml&lt;/param-value&gt;
	&lt;/context-param&gt;

	&lt;listener&gt;  
		&lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;  
	&lt;/listener&gt;

        &lt;filter&gt;
		&lt;filter-name&gt;vraptor&lt;/filter-name&gt;
		&lt;filter-class&gt;br.com.caelum.vraptor.VRaptor&lt;/filter-class&gt;
	&lt;/filter&gt;

	&lt;filter-mapping&gt;
		&lt;filter-name&gt;vraptor&lt;/filter-name&gt;
		&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
	&lt;/filter-mapping&gt;

	&lt;filter&gt;
		&lt;filter-name&gt;openSessionInViewFilter&lt;/filter-name&gt;
		&lt;filter-class&gt;org.springframework.orm.hibernate3.support.OpenSessionInViewFilter&lt;/filter-class&gt;
		&lt;init-param&gt;
			&lt;param-name&gt;sessionFactoryBeanName&lt;/param-name&gt;
			&lt;param-value&gt;annotationSessionFactory&lt;/param-value&gt;
		&lt;/init-param&gt;
	&lt;/filter&gt;

	&lt;filter-mapping&gt;
		&lt;filter-name&gt;openSessionInViewFilter&lt;/filter-name&gt;
		&lt;url-pattern&gt;/*&lt;/url-pattern&gt;  
    &lt;/filter-mapping&gt;

Ainda está dando LazyInitializationException: failed to lazily initialize a collection of role

O que posso fazer?

Obrigado

inverte a ordem de declaração dos filtros… deixa o do spring antes do do vraptor

Apareceu outro probema, no openSessionInViewFilter preciso passar um sessionFactoryBeanName, mas eu não tenho no applicationContext.xml só tenho entityManagerFactory

	&lt;filter&gt;
		&lt;filter-name&gt;openSessionInViewFilter&lt;/filter-name&gt;
		&lt;filter-class&gt;org.springframework.orm.hibernate3.support.OpenSessionInViewFilter&lt;/filter-class&gt;
		&lt;init-param&gt;
			&lt;param-name&gt;sessionFactoryBeanName&lt;/param-name&gt;
			&lt;param-value&gt;annotationSessionFactory&lt;/param-value&gt;
		&lt;/init-param&gt;
	&lt;/filter&gt;

então vc precisa do OpenEntityManagerInVIewFilter

Deu certo.

Obrigado pela ajuda.