LazyInitializationException (JBoss 5.x, Hibernate 3.3.2) [CONT.]

Boa tarde a todos…

Estou com um problema um tanto chato, acho que muitos dos que já trabalharam com Hibernate e J2EE já devem ter se deparado com ele. Estou completando 7 dias hoje, em debugs incansáveis e pesquisas pra resolver esse problema. Apesar de ser um problema que envolve Hibernate, postei na seção de Web pois tem muito mais haver. Primeiramente, alguns trechos de código:

Struts.xml, trecho com Interceptor.

[code]

(…)


		<interceptor-stack name="IntegraStack">
			<interceptor-ref name="Seguranca" />
			<interceptor-ref name="defaultStack" />
		</interceptor-stack>
	</interceptors>[/code]

Web.xml, trecho com Servlet Filter.

<filter> <display-name>HibernateSessionFilter</display-name> <filter-name>HibernateSessionFilter</filter-name> <filter-class>net.m21xx.integra.helpers.HibernateSessionFilter</filter-class> </filter> <filter-mapping> <filter-name>HibernateSessionFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

Hibernate.cfg.xml, omitindo detalhes do acesso ao banco.

[code]

org.gjt.mm.mysql.Driver
jdbc:mysql://localhost:3306/integra
(…)
2
false
on_close

    <property name="hibernate.default_schema">integra</property>        
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
    
     <property name="hibernate.transaction.factory_class">org.hibernate.transaction.JTATransactionFactory</property>
    <property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</property>
    <property name="hibernate.transaction.auto_close_session">false</property>
    <property name="hibernate.transaction.flush_before_completion">false</property>
    
    <property name="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
    
    <property name="hibernate.current_session_context_class">jta</property>
    
    <property name="hibernate.show_sql">false</property>

    <mapping resource="mapeamento.hbm.xml"/>
</session-factory>
[/code]

Mapeamento das classes envolvidas no problema.

[code]









<class name="UsuariosVO" table="usuarios">
	<id name="id">
		<generator class="native" />
	</id>
	<property name="nome" column="usuario" />
	<property name="senha" />	
	<property name="habilitado" />
	<property name="dataCriacao" column="tsDataCriacao" />
	<property name="ultimoLogin" column="tsUltimoLogin" />
	<bag name="grupos" lazy="true" table="usuarios_grupos">
		<key column="usuarioId" />
		<many-to-many column="grupoId" class="GruposVO" />
	</bag>		
	<bag name="sessoes" lazy="true" inverse="true">
		<key column="usuarioId" />
		<one-to-many class="SessoesVO" />
	</bag>		
</class>

[/code]

Action Home, que é acessada após login no sistema.

public class ActHome extends BaseAction { public String execute() throws Exception { // Executa código comum ás páginas super.execute(); // TODO preencher com algo - página inicial do sistema! (blog?) setUsuario(base_usuario); return SUCCESS; } /* Teste */ private UsuariosVO usuario; public UsuariosVO getUsuario() { return usuario; } public void setUsuario(UsuariosVO pUsuario) { usuario = pUsuario; } }

E finalmente a raiz do problema. Home.jsp.

[code]<%@ page language=“java” contentType=“text/html; charset=UTF-8” pageEncoding=“UTF-8”%>
<%@ taglib prefix=“s” uri="/struts-tags" %>

[/code]

Sandbox p/ teste de tais configurações, numa aplicação console (J2SE).

		Session session = HibernateUtil.getSessionFactory().openSession();
		
		System.out.println(session.hashCode());
		
		ArrayList<UsuariosVO> lItems = (ArrayList<UsuariosVO>) session.createQuery("from UsuariosVO").list();
		UsuariosVO lUsuario = lItems.get(0);
		System.out.println(lUsuario.getNome());
		
		System.out.println(session.hashCode());

		ArrayList<GruposVO> lItems2 = (ArrayList<GruposVO>) session.createQuery("from GruposVO").list();
		GruposVO lGrupo = lItems2.get(0);
		System.out.println(lGrupo.getNome());
		
		System.out.println(session.hashCode());

		Collection<GruposVO> lGrupos = lUsuario.getGrupos();
		System.out.println(lGrupos.size());
		Iterator<GruposVO> lIterator = lGrupos.iterator();
		while (lIterator.hasNext())
		{
			GruposVO lGrupoIt = lIterator.next();
			System.out.println(lGrupoIt.getNome());
		}
		
		System.out.println(session.hashCode());

		Collection<UsuariosVO> lUsuarios = lGrupo.getUsuarios();
		System.out.println(lUsuarios.size());
		Iterator<UsuariosVO> lIterator2 = lUsuarios.iterator();
		while (lIterator2.hasNext())
		{
			UsuariosVO lUsuarioIt = lIterator2.next();
			System.out.println(lUsuarioIt.getNome());
		}
		
		System.out.println(session.hashCode());
		
		session.close();[/code]

Ok, explicando agora. Estou codificando um sistema, que precisa de autenticação e autorização. Durante o desenvolvimento surgiu a necessidade de testar o acesso aos dados e se o mapeamento estava correto. Então, coloquei um atributo "usuario" alimientado com base_usuario (o código super...() carrega com um Objeto contendo detalhes do usuário, descritos no mapeamento). No JSP que faz uso dessa Action, coloquei um Iterator e ai o problema se instalou.

[quote]root cause

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: net.m21xx.integra.domain.models.UsuariosVO.grupos, no session or session was closed[/quote]

De acordo com minhas pesquisas, configurações e o manual do Hibernate, toda sessão tem um tempo de vida, definido em configuração, que por padrão fecha a sessão após o fim da transação, dispensando a necessidade do programador fechar a sessão (e/ou a transação) após o acesso aos dados no seu EJB (ou Action, em caso de acesso direto). O erro que foi disparado foi causado por uma parte do Objeto persistente que não foi inicializada por estar em modo LAZY (faz-se o acesso on-demand, e não ao chamar o load()).

Acontece que este é um mapeamento *ToMany (many-to-many nesse caso), que, por questões de massa de dados e de performance, deve permanescer em LAZY (estas chamadas de usuários e grupos são feitas mais de uma vez a cada request).

Nas buscas por uma solução, eu encontrei algo que poderia me ajudar. Se funcionasse. Se chama "Open Session In View". É uma "técnica" que mantém a sessão Hibernate ativa antes mesmo da Action entrar em execução, passando pela renderização dos JSP necessários para montar a View (e assim dando a chance de o Hibernate fazer uso da sessão para preencher os dados LAZY do objeto).

Acontece que não funciona. Tentei também, usar MBeans do JBoss para prover o acesso ao Hibernate e ao Banco de dados via JNDI. Sem sucesso para o problema. Segue o MBean:
[code]<server>
	<mbean code="org.hibernate.jmx.HibernateService" name="jboss.jca:service=HibernateFactory,name=HibernateFactory">
		<!-- Required services -->
		<depends>jboss.jca:service=LocalTxCM,name=IntegraDS</depends>

		<!-- Bind the Hibernate service to JNDI -->
		<attribute name="JndiName">java:/hibernate/SessionFactory</attribute>

		<!-- Datasource settings -->
		<attribute name="Datasource">java:IntegraDS</attribute>
		<attribute name="Dialect">org.hibernate.dialect.MySQL5Dialect</attribute>

		<!-- Transaction integration -->
		<attribute name="TransactionStrategy">org.hibernate.transaction.JTATransactionFactory</attribute>
		<attribute name="TransactionManagerLookupStrategy">org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
		<attribute name="FlushBeforeCompletionEnabled">false</attribute>
		<attribute name="AutoCloseSessionEnabled">false</attribute>

		<!-- Fetching options -->
		<attribute name="MaximumFetchDepth">5</attribute>

		<!-- Second-level caching -->
		<attribute name="SecondLevelCacheEnabled">false</attribute>
		<attribute name="CacheProviderClass">org.hibernate.cache.NoCacheProvider</attribute>
		<attribute name="QueryCacheEnabled">false</attribute>

		<!-- Logging -->
		<attribute name="ShowSqlEnabled">true</attribute>

		<!-- Mapping files -->
		<attribute name="MapResources">mapeamento.hbm.xml</attribute>
	</mbean>
</server>

O MBean me trouxe outro problema. Nem todas as configurações que fazemos no XML podem ser feitas no MBean, por não existirem atributos mapeados (ou explicitados no manual) para devido fim.

Como podem ver nas amostras de código acima, usei uma ServletFilter e um StrutsInterceptor para tentar sanar o problema. Porém, ao chamar o hashCode, observei no Log do JBoss que a sessão mudou (coloquei org.hibernate em modo TRACE e vi a mudança, forçando a destruição da sessão), portanto, os dados que eram para ser usados pela chamada LAZY já não estariam mais disponíveis. Podem notar também que as configurações estão usando JTA no contexto JBoss. Passei a usar JTA na esperança da UserTransaction me ajudar, mas a sessão (ou a transação, vai saber…) está morrendo antes de chegar na View!

Seguem alguns dos links que usei na minha pesquisa. Diga-se de passagem, também consultei o manual.
http://www.javalobby.org/java/forums/t20533.html
http://www.jroller.com/kbaum/entry/orm_lazy_initialization_with_dao
http://www.guj.com.br/posts/list/15/133184.java#719514
https://www.hibernate.org/43.html

Estes são apenas alguns, meu histórico é grande e não dura muito tempo (apago todo dia). Eu acredito que seja algo com o JTA/UserTransaction… usei todas as configurações que pude no Hibernate (deixei tudo no manual, até flush() to usando hehe). Alguma idéia?

Segue um trecho de log que capturei agora a pouco, com o Hibernate em modo TRACE, reparem a linha aonde ele identifica a liberação da sessão como on_close e em seguida fecha “automaticamente” a sessão!

[quote]2010-01-09 09:33:45,593 TRACE [org.hibernate.event.def.AbstractFlushingEventListener] (http-0.0.0.0-8080-1) executing flush
2010-01-09 09:33:45,593 TRACE [org.hibernate.jdbc.ConnectionManager] (http-0.0.0.0-8080-1) registering flush begin
2010-01-09 09:33:45,593 TRACE [org.hibernate.jdbc.ConnectionManager] (http-0.0.0.0-8080-1) registering flush end
2010-01-09 09:33:45,593 TRACE [org.hibernate.event.def.AbstractFlushingEventListener] (http-0.0.0.0-8080-1) post flush
2010-01-09 09:33:45,593 TRACE [org.hibernate.jdbc.JDBCContext] (http-0.0.0.0-8080-1) before transaction completion
2010-01-09 09:33:45,593 TRACE [org.hibernate.impl.SessionImpl] (http-0.0.0.0-8080-1) before transaction completion
2010-01-09 09:33:45,593 DEBUG [org.hibernate.transaction.JDBCTransaction] (http-0.0.0.0-8080-1) committed JDBC Connection
2010-01-09 09:33:45,593 TRACE [org.hibernate.jdbc.JDBCContext] (http-0.0.0.0-8080-1) after transaction completion
2010-01-09 09:33:45,593 DEBUG [org.hibernate.jdbc.ConnectionManager] (http-0.0.0.0-8080-1) transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
2010-01-09 09:33:45,593 TRACE [org.hibernate.impl.SessionImpl] (http-0.0.0.0-8080-1) after transaction completion
2010-01-09 09:33:45,593 TRACE [org.hibernate.impl.SessionImpl] (http-0.0.0.0-8080-1) automatically closing session
2010-01-09 09:33:45,593 TRACE [org.hibernate.impl.SessionImpl] (http-0.0.0.0-8080-1) closing session
2010-01-09 09:33:45,593 TRACE [org.hibernate.jdbc.ConnectionManager] (http-0.0.0.0-8080-1) performing cleanup
2010-01-09 09:33:45,593 DEBUG [org.hibernate.jdbc.ConnectionManager] (http-0.0.0.0-8080-1) releasing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
2010-01-09 09:33:45,593 TRACE [org.hibernate.connection.DriverManagerConnectionProvider] (http-0.0.0.0-8080-1) returning connection to pool, pool size: 1
2010-01-09 09:33:45,593 TRACE [org.hibernate.jdbc.JDBCContext] (http-0.0.0.0-8080-1) after transaction completion
2010-01-09 09:33:45,593 DEBUG [org.hibernate.jdbc.ConnectionManager] (http-0.0.0.0-8080-1) transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
2010-01-09 09:33:45,593 TRACE [org.hibernate.impl.SessionImpl] (http-0.0.0.0-8080-1) after transaction completion
2010-01-09 09:33:45,593 TRACE [org.hibernate.context.ThreadLocalSessionContext] (http-0.0.0.0-8080-1) allowing proxied method [hashCode] to proceed to real session
2010-01-09 09:33:45,593 TRACE [net.m21xx.integra.domain.base.BaseDAO] (http-0.0.0.0-8080-1) Session now is 25411043
2010-01-09 09:33:45,609 TRACE [net.m21xx.integra.utils.HibernateUtil] (http-0.0.0.0-8080-1) Getting current SessionFactory
2010-01-09 09:33:45,609 DEBUG [org.hibernate.impl.SessionImpl] (http-0.0.0.0-8080-1) opened session at timestamp: 12630404256
2010-01-09 09:33:45,609 TRACE [org.hibernate.context.ThreadLocalSessionContext] (http-0.0.0.0-8080-1) allowing proxied method [hashCode] to proceed to real session
2010-01-09 09:33:45,609 TRACE [net.m21xx.integra.domain.base.BaseDAO] (http-0.0.0.0-8080-1) Session before was 23602427
2010-01-09 09:33:45,609 TRACE [org.hibernate.context.ThreadLocalSessionContext] (http-0.0.0.0-8080-1) allowing method [beginTransaction] in non-transacted context
2010-01-09 09:33:45,609 TRACE [org.hibernate.context.ThreadLocalSessionContext] (http-0.0.0.0-8080-1) allowing proxied method [beginTransaction] to proceed to real session
2010-01-09 09:33:45,609 DEBUG [org.hibernate.transaction.JDBCTransaction] (http-0.0.0.0-8080-1) begin
2010-01-09 09:33:45,609 DEBUG [org.hibernate.jdbc.ConnectionManager] (http-0.0.0.0-8080-1) opening JDBC connection
[/quote]

Alguma idéia? Ninguém? :frowning:

Olá Marcos.

Conseguiu resolver teu problema? Estou com o mesmo problema com mapeamentos @ManyToMany, carrego com FETCH JOIN, mas quando vou acessar da erro.

Nada ainda… meu mapeamento também é ManyToMany, configurado pra Lazy…

Marcos, bom dia.

Onde vc faz:
session.createQuery(“from UsuariosVO”).list(), troca por:

Query query = session.createQuery(“SELECT u FROM UsuariosVO u INNER JOIN FETCH u.grupos g”);
List usuarios = query.list();
for(UsuariosVO u : usuarios) {
u.getGrupos().size();
}
e retira o segundo sql session.createQuery(“from GruposVO”).list().
Eu resolvi assim, porém eu trago apenas 1 usuário com seus grupos. Estou usando EJB e não quero utilizar o padrão OpenSessionInViewFilter.

Rodrigo, sua idéia é boa, vou testá-la.

Mas estou pensando também em usar o OpenSession~ do Spring, já vi alguem usar em conjunto com o Struts e dizem q funciona… estou olhando as sources, e se nao por possível vou me basear na classe pra escrever um filter usando ThreadLocal (o q não é recomendado)

Marcos,
uso o spring em outros projetos e é muito bom o framework como um todo e o filtro vai suprir sua necessidade sem dúvida, o porém de usar o filtro é a quantidade de sql que podem ser geradas(sql dentro de loop) se você não tomar cuidado. Agora se vc monitorar os sql que são gerados durante a fase de desenvolvimento não terá problemas.
Um exemplo é o sql que vc fez, se vc tiver 500 usuários com 5 grupos cada, é só monitorar os logs que terá o resultado de não usar o filtro de maneira correta.

Qual a versão do Hibernate que vocês estão usando? Depois desse erro, tenho q tentar outra versão, é o jeito!!!

[quote]2010-01-22 14:43:14,671 TRACE [net.m21xx.integra.utils.HibernateUtil] (http-0.0.0.0-8080-1) Getting current SessionFactory
2010-01-22 14:43:14,671 TRACE [net.m21xx.integra.utils.HibernateUtil] (http-0.0.0.0-8080-1) Current thread ID is 75
2010-01-22 14:43:14,671 TRACE [net.m21xx.integra.domain.base.BaseDAO] (http-0.0.0.0-8080-1) Session is 12465902
2010-01-22 14:43:14,671 DEBUG [org.hibernate.transaction.JTATransaction] (http-0.0.0.0-8080-1) begin
2010-01-22 14:43:14,671 DEBUG [org.hibernate.engine.Collections] (http-0.0.0.0-8080-1) Collection found: [net.m21xx.integra.domain.models.UsuariosVO.grupos#1], was: [net.m21xx.integra.domain.models.UsuariosVO.grupos#1] (uninitialized)
2010-01-22 14:43:14,671 DEBUG [org.hibernate.engine.Collections] (http-0.0.0.0-8080-1) Collection found: [net.m21xx.integra.domain.models.UsuariosVO.sessoes#1], was: [net.m21xx.integra.domain.models.UsuariosVO.sessoes#1] (uninitialized)
2010-01-22 14:43:14,671 DEBUG [org.hibernate.SQL] (http-0.0.0.0-8080-1) select usuariosvo0_.id as id107_, usuariosvo0_.usuario as usuario107_, usuariosvo0_.senha as senha107_, usuariosvo0_.habilitado as habilitado107_, usuariosvo0_.tsDataCriacao as tsDataCr5_107_, usuariosvo0_.tsUltimoLogin as tsUltimo6_107_ from integra.usuarios usuariosvo0_ where 1=1 and usuariosvo0_.usuario=?
2010-01-22 14:43:14,687 DEBUG [org.hibernate.engine.StatefulPersistenceContext] (http-0.0.0.0-8080-1) initializing non-lazy collections
2010-01-22 14:43:14,687 DEBUG [org.hibernate.transaction.JTATransaction] (http-0.0.0.0-8080-1) commit
2010-01-22 14:43:14,687 TRACE [net.m21xx.integra.utils.HibernateUtil] (http-0.0.0.0-8080-1) Getting current SessionFactory
2010-01-22 14:43:14,687 TRACE [net.m21xx.integra.utils.HibernateUtil] (http-0.0.0.0-8080-1) Current thread ID is 75
2010-01-22 14:43:14,687 INFO [STDOUT] (http-0.0.0.0-8080-1) Session is 12465902
2010-01-22 14:43:14,687 ERROR [org.hibernate.LazyInitializationException] (http-0.0.0.0-8080-1) failed to lazily initialize a collection of role: net.m21xx.integra.domain.models.UsuariosVO.grupos, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: net.m21xx.integra.domain.models.UsuariosVO.grupos, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:119)
at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248)
at net.m21xx.integra.controllers.restrito.ActHome.execute(ActHome.java:24)
(…)
[/quote]

Nessa situação, coloquei uma UserTransaction dentro do filtro…

[code] Session lSession = null;
UserTransaction tx = null;

	try
	{
		try
		{
			logger.trace("Abrindo transação do usuário...");
			tx = (UserTransaction) new InitialContext()	.lookup("java:comp/UserTransaction");
			tx.begin();
			logger.trace("UTX is " + tx.hashCode());

			logger.trace("Opening Hibernate session");
			lSession = HibernateUtil.getSessionFactory().getCurrentSession();
			logger.trace("Session is " + lSession.hashCode());

			chain.doFilter(request, response);
		}
		finally
		{
			logger.trace("Session is " + lSession.hashCode());
			if (lSession.isOpen())
			{
				lSession.close();
			}
			else
			{
				logger.debug("AVISO: Sessao ja foi fechada!");
			}
			
			logger.trace("Fechando transação do usuário...");
			tx.commit();
		}
	}
	catch (NamingException e)
	{
		e.printStackTrace();
	}
	catch (NotSupportedException e)
	{
		e.printStackTrace();
	}
	catch (SystemException e)
	{
		e.printStackTrace();
	}
	catch (HeuristicRollbackException e)
	{
		e.printStackTrace();
	}		
	catch (HeuristicMixedException e)
	{
		e.printStackTrace();
	}
	catch (RollbackException e)
	{
		e.printStackTrace();
	}[/code]

E fiz essa loucura na minha Action, só pra ver se carregava… essa primeira serviu pra emitir (e constatar) que a sessão nao mudou…

Session sess = HibernateUtil.getSessionFactory().getCurrentSession(); System.out.println("Session is " + sess.hashCode()); setUsuario(base_usuario); base_usuario.getGrupos().size();

=(

Pessoal, criei um meio de manter a mesma sessão, mas o erro persiste. Tanto com o UserTransaction quanto o ThreadLocal a sessão se mantém, mas o filtro parece não alcançar a renderização do JSP…

Código dentro do HibernateUtil

[code] @SuppressWarnings(“unchecked”)
public static Session getThreadSession(boolean pCreate)
{
Session lSession = (Session) sessionLocal.get();

	if (lSession == null)
	{
		if (pCreate)
		{
			lSession = getSessionFactory().openSession();
			sessionLocal.set(lSession);
		}
	}
	else
	{
		if (!lSession.isOpen())
		{
			lSession = null;
			sessionLocal.set(lSession);
		}
	}
	
	return lSession;
}[/code]

Será q tem algo de errado no meu web.inf?

[code]<?xml version="1.0" encoding="UTF-8"?>

<display-name>Integra: Aplicação Web</display-name>

<session-config>
	<session-timeout>86400</session-timeout>
</session-config>

<context-param>
	<param-name>org.apache.tiles.DEFINITIONS_CONFIG</param-name>
	<param-value>/WEB-INF/tiles.xml</param-value>
</context-param>

<listener>
	<listener-class>org.apache.struts2.tiles.StrutsTilesListener</listener-class>
</listener>

<filter>
	<display-name>SessionIdFilter</display-name>
	<filter-name>SessionIdFilter</filter-name>
	<filter-class>net.m21xx.integra.helpers.SessionIdFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>SessionIdFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
	<display-name>HibernateSessionFilter</display-name>
	<filter-name>HibernateSessionFilter</filter-name>
	<filter-class>net.m21xx.integra.helpers.HibernateSessionFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>HibernateSessionFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
	<filter-name>struts2</filter-name>
	<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>struts2</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

<welcome-file-list>
	<welcome-file>index.html</welcome-file>
	<welcome-file>index.htm</welcome-file>
	<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

[/code]

Caros Gujinianos,

Após meche daqui meche de lá, descobri o q estava errado. A exceção LazyInitializationException é dispadara não apenas quando a sessão está fechada, mas também quando o objeto a ser inicializado foi fechado por conta de outra consulta que veio depois!

Observem a Action…

[code] public String execute() throws Exception
{
// Executa código comum ás páginas
super.execute();

	// TODO preencher com algo - página inicial do sistema! (blog?)
	
	//Session sess = HibernateUtil.getSessionFactory().getCurrentSession();
	Session sess = HibernateUtil.getThreadSession();
	System.out.println("Session is " + sess.hashCode());
	
	ArrayList<UsuariosVO> arr = (ArrayList<UsuariosVO>) sess.createQuery("from UsuariosVO").list();
	UsuariosVO usr = arr.get(0);

	setUsuario(usr); // não dá erro, pois foi acessada por último (nem necessita de .size()!)
	
	setUsuario(base_usuario); //  erro na JSP, e se habilitar a próx. linha, dá erro aqui na action
	//base_usuario.getGrupos().size();

	return SUCCESS;
}[/code]

Essa variável base_usuário vem da superclasse, que faz parte do procedimento comum a várias outras Actions (vem antes do código que prepara conteúdo para a View).

[code]public class BaseAction extends ActionSupport
{

private static final long serialVersionUID = 1L;

/* Conteúdo protegido, acessado pelas Actions herdeiras */

protected UserContext base_userCtx;

protected SegurancaEJBIf base_ejbSeguranca;

protected NavegacaoEJBIf base_ejbNavegacao;

protected UsuariosVO base_usuario;

/* Código comum á todas as Action - DEVE SER EXECUTADO NO INICIO! */

public String execute() throws Exception
{
	// Contexto do usuario
	base_userCtx = UserContext.getContext();

	// Carrega os EJBs a serem usados
	InitialContext ic = new InitialContext();
	base_ejbSeguranca = (SegurancaEJBIf) ic.lookup("ejb/Seguranca");
	base_ejbNavegacao = (NavegacaoEJBIf) ic.lookup("ejb/Navegacao");

	// Nome de usuario -> Objeto do usuário
	base_usuario = base_ejbSeguranca.obterUsuario(base_userCtx.getUsername());

	// Carrega conteúdo comum ás páginas
	configuraMenuLateral(base_usuario);
	carregaMensagensAnuncio(base_usuario);

	return null;
}[/code]

Agora algo me deixou na dúvida. O erro também pode ter acontecido por conta da variável estar declarada como protected? Ou isso daria erro de compilação? (dá pra escrever um livro só sobre essa exception rsrs)

Obs.: testifiquei a conclusão acima usando o ManagedSessionContext e a função getThreadSession que fiz como workaround pra solucionar meu problema. Usando o método normal de filtro+getCurrentSession+transação e o ThreadLocalSessionContext, acontece a mesma situação (variável antiga se perde em detrimento da última query).

Agora quero ver se alguém responde essa…

[code] public String execute() throws Exception
{
// Executa código comum ás páginas
super.execute();
//setUsuario(base_usuario);

	// TODO preencher com algo - página inicial do sistema! (blog?)
	
	Session sess = HibernateUtil.getSessionFactory().getCurrentSession();		
	ArrayList<UsuariosVO> arr = (ArrayList<UsuariosVO>) sess.createQuery("from UsuariosVO").list();
	UsuariosVO usr = arr.get(0);		
	setUsuario(usr);
	
	//InitialContext ic = new InitialContext();
	//SegurancaEJBIf ejbSeguranca = (SegurancaEJBIf) ic.lookup("ejb/Seguranca");
	//UsuariosVO u = ejbSeguranca.obterUsuario(base_userCtx.getUsername());
	//setUsuario(u);
	
	return SUCCESS;
}[/code]

Nesse código (Action Home), existem 3 setUsuario. Porque apenas o segundo não dá erro? Segue o código do super.execute():

[code] public String execute() throws Exception
{
// Contexto do usuario
base_userCtx = UserContext.getContext();

	// Carrega os EJBs a serem usados
	InitialContext ic = new InitialContext();
	base_ejbSeguranca = (SegurancaEJBIf) ic.lookup("ejb/Seguranca");
	base_ejbNavegacao = (NavegacaoEJBIf) ic.lookup("ejb/Navegacao");

	// Nome de usuario -> Objeto do usuário
	base_usuario = base_ejbSeguranca.obterUsuario(base_userCtx.getUsername());

	// Carrega conteúdo comum ás páginas
	configuraMenuLateral(base_usuario);
	carregaMensagensAnuncio(base_usuario);

	return null;
}[/code]

Eai? Alguém se habilita?

Pessoal,

vendo em um trecho de código por aí, vi que uma maneira de contornar é forçar o carregamento quando necessário… foi ai que me ocorreu de colocar isso antes e depois da chamada do EJB. Daí… não aconteceu nenhuma exceção! Ou seja, dentro dos limites do EJB, a sessão Hibernate e os objetos ficam “ativos” para serem manipulados… pelo menos foi o q eu percebi com tudo isso. Quando a chamada Lazy era feita direto pela View, a sessão atual não pode fazer nada, pois está dentro do limite da chamada EJB (que já se desfez!). Eai, pensei certo? É algo com colocar a chamada do EJB no meio desse bolo doido não é?

Antes (com erro)

@Stateless(mappedName = "ejb/Seguranca") public class SegurancaEJB implements SegurancaEJBIf { public UsuariosVO obterUsuario(String pUsuario) { return BOFactory.getSegurancaBO().obterUsuario(pUsuario); }
Depois (sem erro)

@Stateless(mappedName = "ejb/Seguranca") public class SegurancaEJB implements SegurancaEJBIf { public UsuariosVO obterUsuario(String pUsuario) { UsuariosVO o = BOFactory.getSegurancaBO().obterUsuario(pUsuario); o.getGrupos().size(); return o; }

A pedido, link do código completo (compactado com 7z, e dump SQL).

Application Server: JBoss AS 5.1.0
Banco de dados: MySQL 5.0.85

Struts, Hibernate e Tiles já inclusos nas libs. Copiar direto no workspace do Eclipse e importar.

Links:
http://www.mediafire.com/file/mxzvn1djhzj/workspace.7z
http://www.mediafire.com/file/3ttndkinnmy/integra.sql

Resumo:
Tenho vários mapeamentos LAZY, e na primeira tentativa de chamar uma List de um objeto (ainda dentro da Action, não é nem no JSP!!!) o servidor explode e retorna o LazyInitializationException.

Log das últimas execuções:
http://www.mediafire.com/file/mq2iwdm2d1y/Cópia%20de%20server.7z

Marcos

Poste pra gente o seguinte: 1. a stacktrace completa do erro (e apenas ela) 2. o codigo o qual essa stacktrace se refere 3. o codigo o qual carrega essa entidade que esta disparando a exception.

O Open session in view vai resolver, mas se voce esta usando EJB3 e passando o objeto para outro tier, isso nao sera o suficiente.

Oi Paulo,

Fiz um código paralelo que reproduz o mesmo erro aqui, segue os detalhes…

Log do erro (ponto de falha no JSP)

[quote]2010-07-02 23:38:04,890 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/moduloWeb].[jsp]] (http-0.0.0.0-8080-1) Servlet.service() for servlet jsp threw exception
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.sandbox.domain.models.FacetObjectsVO.values, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:365)
at org.hibernate.collection.AbstractPersistentCollection.read(AbstractPersistentCollection.java:108)
at org.hibernate.collection.PersistentBag.iterator(PersistentBag.java:272)
at org.apache.struts2.util.MakeIterator.convert(MakeIterator.java:82)
at org.apache.struts2.components.IteratorComponent.start(IteratorComponent.java:270)
at org.apache.struts2.views.jsp.ComponentTagSupport.doStartTag(ComponentTagSupport.java:53)
at org.apache.jsp.WEB_002dINF.pages.index_jsp._jspx_meth_s_005fiterator_005f0(index_jsp.java:185)
at org.apache.jsp.WEB_002dINF.pages.index_jsp._jspService(index_jsp.java:96)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:369)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:322)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:249)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:638)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:444)
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:382)
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:310)
at org.apache.struts2.dispatcher.ServletDispatcherResult.doExecute(ServletDispatcherResult.java:154)
at org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:186)
at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:362)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:266)
at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:165)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:252)
at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:122)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:195)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:195)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:179)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:75)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:94)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:235)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:89)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:130)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:267)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:126)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:138)
at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:165)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:179)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:176)
at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:52)
at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:488)
at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.sandbox.struts.filters.SessionIdFilter.doFilter(SessionIdFilter.java:87)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190)
at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126)
at org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:598)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Unknown Source)
[/quote]

Log de erro (ponto de falha na Action)

[quote]
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.sandbox.domain.models.FacetObjectsVO.values, 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.PersistentBag.size(PersistentBag.java:248)
com.sandbox.struts.controller.ActHome.execute(ActHome.java:21)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
java.lang.reflect.Method.invoke(Unknown Source)
com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:441)
com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:280)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:243)
com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:165)
com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:252)
org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:122)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:195)
com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:195)
com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:179)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:75)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:94)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:235)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:89)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:130)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:267)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:126)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:138)
com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:87)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:165)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:179)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:176)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:237)
org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:52)
org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:488)
org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
com.sandbox.struts.filters.SessionIdFilter.doFilter(SessionIdFilter.java:87)
org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)[/quote]

Modulo Web, Action Home.do

[code]package com.sandbox.struts.controller;

import javax.naming.InitialContext;

import com.opensymphony.xwork2.ActionSupport;
import com.sandbox.business.beans.FacetObjectsEJBIf;
import com.sandbox.domain.models.FacetObjectsVO;
import com.sandbox.utils.Constants;

public class ActHome extends ActionSupport
{

private static final long serialVersionUID = 1L;

@Override
public String execute() throws Exception
{
	InitialContext ic = new InitialContext();
	FacetObjectsEJBIf ejb = (FacetObjectsEJBIf) ic.lookup("ejb/FacetObjects");
	facet = ejb.fetchFacet("Gênero Musical");
	facet.getValues().size();
	
	return Constants.RESULT_HOME;
}

private FacetObjectsVO facet;

public FacetObjectsVO getFacet()
{
	return facet;
}

public void setFacet(FacetObjectsVO pFacet)
{
	facet = pFacet;
}

}[/code]

Hibernate Filter, ThreadLocal

[code]package com.sandbox.struts.filters;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sandbox.utils.HibernateSession;

public class HibernateFilter implements Filter
{

private static final Logger logger = LoggerFactory.getLogger(HibernateFilter.class);

public HibernateFilter()
{
	
}

public void init(FilterConfig fConfig) throws ServletException
{
	logger.info("Iniciando filtro.");
}

public void destroy()
{
	logger.info("Finalizando filtro.");
}

public void doFilter(ServletRequest pRequest, ServletResponse pResponse, FilterChain pChain)
	throws IOException, ServletException
{
	logger.debug("Filtro executando...");
	
	Session lSession = HibernateSession.getCurrentSession();
	
	pChain.doFilter(pRequest, pResponse);
	
	if (lSession.isOpen())
	{
		logger.debug("Closing session is " + lSession.hashCode());
	}
	else
	{
		logger.debug("AVISO: Sessao ja foi fechada!");
	}

	HibernateSession.closeSession();
	
	logger.debug("Filtro executado com sucesso.");
}

}
[/code]

struts.xml

<struts> <package namespace="/" name="Acts" extends="struts-default"> <action name="Home" class="com.sandbox.struts.controller.ActHome"> <result name="home">WEB-INF/pages/index.jsp</result> </action> </package> </struts>

web.xml

[code] ModuloWeb

<session-config>
	<session-timeout>600</session-timeout>
</session-config>

<filter>
	<display-name>SessionIdFilter</display-name>
	<filter-name>SessionIdFilter</filter-name>
	<filter-class>com.sandbox.struts.filters.SessionIdFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>SessionIdFilter</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
	<filter-name>struts2</filter-name>
	<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
	<filter-name>struts2</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>

<welcome-file-list>
	<welcome-file>index.html</welcome-file>
	<welcome-file>index.htm</welcome-file>
	<welcome-file>index.jsp</welcome-file>
</welcome-file-list>[/code]

index.jsp

[code]

<s:if test=“pageTitle != null”><s:property value=“pageTitle” /></s:if>

<link rel="stylesheet" type="text/css" href="<%=request.getContextPath() %>/styles/template.css" />
This is the header page.
Menu.
O início de tudo.

Valores:
This is the footer page.
[/code]

Modulo EJB, Hibernate Session

[code]package com.sandbox.utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

public class HibernateSession
{
public static final ThreadLocal session = new ThreadLocal();

public static Session getCurrentSession()
{
	Session s = (Session) session.get();
	if (s == null)
	{
		SessionFactory sf = HibernateUtil.getSessionFactory();
		s = sf.openSession();
		session.set(s);
	}

	return s;
}

public static void closeSession()
{
	Session s = (Session) session.get();
	session.set(null);
	if (s != null)
		s.close();
}

}
[/code]

EJB, BaseDAO

[code]package com.sandbox.domain.base;

import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.hibernate.Session;

import com.sandbox.utils.HibernateSession;

public abstract class BaseDAO<TM extends BaseVO, TF extends BaseFilter> implements BaseDAOIf<TM, TF>
{

/* Construtor */

@SuppressWarnings("unchecked")
public BaseDAO()
{
	persistentClass = (Class<TM>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];

	session = HibernateSession.getCurrentSession();
}

/* Acesso protegido */

protected Session session;

/* Atributos */

private Class<TM> persistentClass;

/* Métodos de acesso */

public Class<TM> getPersistentClass()
{
	return persistentClass;
}

/* Operações */

/* CRUD - Create, Retrieve, Update, Delete */

public void inserir(TM pModel)
{
	session.save(pModel);
	session.flush();
}

public void alterar(TM pModel)
{
	session.update(pModel);
	session.flush();
}

public void remover(TM pModel)
{
	session.delete(pModel);
	session.flush();
}

public BaseVO obterPorPK(TM pModel)
{
	Object obj = session.load(getPersistentClass(), pModel.getId());

	return (BaseVO) obj;
}

/* Misc */

@SuppressWarnings("unchecked")
public List<TM> obterTodos()
{
	List<TM> lRet = session.createCriteria(getPersistentClass()).list();

	return lRet;
}

}[/code]

EJB, FacetObjectsVO

[code]package com.sandbox.domain.models;

import java.util.Collection;

import com.sandbox.domain.base.BaseVO;

public class FacetObjectsVO extends BaseVO
{

private static final long serialVersionUID = 1L;

private String title;

private Collection<FacetValuesVO> values;

public String getTitle()
{
	return title;
}

public void setTitle(String pTitle)
{
	title = pTitle;
}

public Collection<FacetValuesVO> getValues()
{
	return values;
}

public void setValues(Collection<FacetValuesVO> pValues)
{
	values = pValues;
}

}
[/code]

EJB, FacetObjectsDAO

[code]package com.sandbox.domain;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;

import com.sandbox.domain.base.BaseDAO;
import com.sandbox.domain.filters.FacetObjectsFilter;
import com.sandbox.domain.models.FacetObjectsVO;

public class FacetObjectsDAO extends BaseDAO<FacetObjectsVO, FacetObjectsFilter>
{

public List<FacetObjectsVO> obterPorFiltro(FacetObjectsFilter pFiltro)
{
	// Mapa de parametros e query inicial
	HashMap<String, Object> lParams = new HashMap<String, Object>();
	StringBuffer lQueryBuf = new StringBuffer("from FacetObjectsVO a where 1=1");

	// Adicionar parametros na clausula WHERE
	if (pFiltro.getTitle() != null)
	{
		lQueryBuf.append(" and a.title = :nome");
		lParams.put("nome", pFiltro.getTitle());
	}

	// Compilar query
	String lHqlQuery = lQueryBuf.toString();
	Query lQuery = session.createQuery(lHqlQuery);

	// Preencher parametros
	Iterator<String> lIter = lParams.keySet().iterator();
	while (lIter.hasNext())
	{
		String lName = lIter.next();
		Object lValue = lParams.get(lName);
		lQuery.setParameter(lName, lValue);
	}

	// Retornar valores
	List<FacetObjectsVO> lRet = lQuery.list();
	 
	return lRet;
}

}
[/code]

FacetObjectsEJB

[code]package com.sandbox.business.beans;

import javax.ejb.Stateless;

import com.sandbox.domain.models.FacetObjectsVO;
import com.sandbox.utils.BOFactory;

@Stateless(mappedName = “ejb/FacetObjects”)
public class FacetObjectsEJB implements FacetObjectsEJBIf
{

public FacetObjectsVO fetchFacet(String pFacetTitle)
{
	return BOFactory.getFacetObjectsBO().fetchFacet(pFacetTitle);
}	

}
[/code]

FacetObjectsBO

[code]package com.sandbox.business;

import java.util.List;

import com.sandbox.domain.FacetObjectsDAO;
import com.sandbox.domain.filters.FacetObjectsFilter;
import com.sandbox.domain.models.FacetObjectsVO;
import com.sandbox.utils.DAOFactory;

public class FacetObjectsBO
{

public FacetObjectsVO fetchFacet(String pFacetTitle)
{
	FacetObjectsFilter lFilter = new FacetObjectsFilter();
	lFilter.setTitle(pFacetTitle);
	
	FacetObjectsDAO lDao = DAOFactory.getUsuariosDAO();
	List<FacetObjectsVO> lRet = lDao.obterPorFiltro(lFilter);
	if (lRet.size() == 1)
	{	
		return lRet.get(0);
	}
	
	return null;
}

}
[/code]

hibernate.cfg.xml

[code]

org.gjt.mm.mysql.Driver
jdbc:mysql://localhost:3306/test

    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password"></property>
    
    <property name="hibernate.connection.pool_size">1</property>
    <property name="hibernate.connection.autocommit">false</property>
    <property name="hibernate.connection.release_mode">on_close</property>
    
    <property name="hibernate.default_schema">test</property>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
    
    <property name="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
    
    <property name="hibernate.current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</property>
    
    <property name="hibernate.show_sql">false</property>
    
    <mapping resource="mapeamento.hbm.xml"/>
</session-factory>
[/code]

mapeamento.hbm.xml

[code]









<class name="FacetValuesVO" table="facetvalues">
	<id name="id" column="id">
		<generator class="native" />
	</id>
	<property name="parent" />
	<property name="title" />	
</class>

[/code]

Ps.: quando a Action está com a linha 21 comentada (.size()), o erro dispara dentro do JSP.

Código simplificado completo:
http://www.mediafire.com/file/mtggyomomwd/workspace-simplificado.7z

Dump SQL usado:
http://www.mediafire.com/file/gn2j3mf2ztz/test.sql