[Vraptor] Lazy Initialization no Interceptor

3 respostas
G

Olá pessoal,

Tenho um componente que guarda o usuário logado
@Component
@SessionScoped
public class Auth {

	private Paciente paciente;
	...

}
E tenho também um inceptor que precisa fazer acessos ao banco de dados:
@Intercepts(after = HibernateInterceptor.class)
public class DaoInterceptor implements Interceptor {

	private final Result result;
	private final Auth auth;
	private final ConvenioDao convenioDao;

	public DaoInterceptor(Result result, Auth auth, ConvenioDao convenioDao) {
		this.result = result;
		this.auth = auth;
		this.convenioDao = convenioDao;
	}

	public boolean accepts(ResourceMethod method) {
		return true;
	}

	public void intercept(InterceptorStack stack, ResourceMethod method,
			Object instance) throws InterceptionException {

		LinkedHashMap<Convenio, Boolean> convenios = new LinkedHashMap<Convenio, Boolean>();
		boolean logado = auth.isLogado()
				&& auth.getPaciente().getConvenios() != null;

		for (Convenio convenio : convenioDao.visualizar()) {
			if (logado) {
				convenios.put(convenio, auth.getPaciente().getConvenios()
						.contains(convenio));
			} else {
				convenios.put(convenio, false);
			}
		}

		result.include("convenios", convenios);
		stack.next(method, instance);
	}
}
Porém, ao fazer auth.getPaciente().getConvenios(), o Hibernate tenta fazer uma LazyInitialization e dá o seguinte erro:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: br.com.metamorfosevirtual.models.Paciente.convenios, could not initialize proxy - no Session
	at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:566)
	at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:186)
	at org.hibernate.collection.internal.AbstractPersistentCollection.readElementExistence(AbstractPersistentCollection.java:293)
	at org.hibernate.collection.internal.PersistentBag.contains(PersistentBag.java:256)
	at br.com.metamorfosevirtual.interceptors.DaoInterceptor.intercept(DaoInterceptor.java:42)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:48)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:67)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:83)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.metamorfosevirtual.interceptors.AuthInterceptor.intercept(AuthInterceptor.java:33)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.metamorfosevirtual.interceptors.HibernateInterceptor.intercept(HibernateInterceptor.java:27)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:44)
	at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:93)
	at br.com.caelum.vraptor.ioc.guice.GuiceProvider.provideForRequest(GuiceProvider.java:82)
	at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:99)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Pelo que eu entendi, o problema seria a falta de uma session do Hibernate. Mas eu achei isso estranho, já que eu recebo um ConvenioDao no construtor do meu interceptor, e esse Dao recebe uma Session do Hibernate no seu construtor. O que pode estar causando esse problema?

3 Respostas

Rafael_Guerreiro

O problema é que a instancia de Paciente que está guardada na classe Auth não foi totalmente carregada.
O fluxo é o seguinte:

[list]O hibernate abre a session “A”[/list]
[list]Pela session “A” você pega um paciente e coloca em Auth[/list]
[list]A session “A” é fechada (ou seja, a instancia ainda existe)[/list]
[list]O hibernate abre a session “B”[/list]
[list]Você tenta acessar uma informação que está em um Paciente[/list]
[list]O hibernate tenta usar a session “A” que está guardada junto com a instancia de Paciente para carregar o restante[/list]
[list]A session “A” está fechada, exception.[/list]

Ou seja, não use entidades em @SessionScoped, mas sim os valores que você precisa. Algo assim:

class AuthPaciente {
   private final Long id;
   private final String name;
   private final AuthConvenio convenio;

   public AuthPaciente(Paciente paciente) {
      id = paciente.getId();
      name = paciente.getName();
      convenio = new AuthConvenio(paciente.getConvenio());
   }

   // getters
}

@SessionScoped
class Auth {
   private AuthPaciente paciente;

   public void load(Paciente paciente) {
      this.paciente = new AuthPaciente(paciente);
   }

   // é interessante usar a lei de Demeter aqui... Ou seja, ao invés de fazer um getPaciente(), fazer um getPacienteId() e um getPacienteName()
}
Hebert_Coelho

Esse post mostra o problema e dá 4 soluções: http://uaihebert.com/?p=1367

G

Hmm entendi. Já corrigi aqui e funcionou.
Valeu pessoal!

Criado 7 de janeiro de 2014
Ultima resposta 7 de jan. de 2014
Respostas 3
Participantes 3