LazyInitializationException con CDI Managed Bean y Stateful Session Bean

Tengo un bean administrado CDI (un bean anotado con @Named que se usa en JSF) que tiene un bean de sesión con estado inyectado. Este bean de sesión es como un servicio, tiene el administrador de entidades (anotado con @PersistenceContext (type = PersistenceContextType.EXTENDED)) y expone los métodos venideros para manipular algunas entidades. Esas entidades están en el bean administrado, que es ConversationScoped. Luego, el JSF llama a un método del bean administrado y el bean administrado llama a algún método del "servicio" (el bean de sesión con estado). No sé si este es el mejor diseño, pero estaba funcionando bien. Pero hay una entidad que tiene algunas colecciones que deben buscarse con LAZY. Y la primera vez que abro la página, parece funcionar bien, pero cuando trato de hacer clic en cualquier botón o hacer alguna acción, tengo la excepción LazyInitializationException. ¿Alguien tiene algún consejo? No sé si hay algo mal. Puse el bean de sesión como con estado y el contexto de persistencia extendido. Este bean de sesión se inyecta dentro del bean administrado, que tiene las entidades. ¿Por qué está lanzando esta excepción? ¿Cómo podría cerrarse el administrador de la entidad?

Este es el código de la entidad que está en problemas:

@Entity
public class ParametrosVingentes implements Serializable {

    public static final String ID = "settings";

    private static final long serialVersionUID = 1L;

    @Id
    private String id;
    @OneToOne
    private ValorHora valorHora;
    @OneToMany
    @JoinTable(
            name="BuscaSistecVingentes",
            joinColumns = @JoinColumn( name="parametros_vingentes_fk"),
            inverseJoinColumns = @JoinColumn( name="agendamento_fk")
    )
    private List<AgendamentoBuscaSistec> agendamentosBuscaSistec;
    @OneToMany
    @JoinTable(
            name="ExportacaoZeusVingentes",
            joinColumns = @JoinColumn( name="parametros_vingentes_fk"),
            inverseJoinColumns = @JoinColumn( name="agendamento_fk")
    )
    private List<AgendamentoExportacaoZeus> agendamentosExportacaoZeus;
    @OneToMany
    @JoinTable(
            name="ImportacaoZeusVingentes",
            joinColumns = @JoinColumn( name="parametros_vingentes_fk"),
            inverseJoinColumns = @JoinColumn( name="agendamento_fk")
    )
    private List<AgendamentoImportacaoZeus> agendamentosImportacaoZeus;

    public ParametrosVingentes() {
    this.id = ID;
    }
// getters and setters...

Este es el bean de sesión con estado:

@Stateful
@LocalBean
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class ParametrosService implements Serializable {

    @PersistenceContext(type= PersistenceContextType.EXTENDED)
    private EntityManager entityManager;

    public void cadastrar(ValorHora valorHora){
        ValorHoraDao valorHoraDao = new ValorHoraDao(entityManager);
        valorHoraDao.salvar(valorHora);
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
        public List<ValorHora> listarValorHora(){
        ValorHoraDao valorHoraDao = new ValorHoraDao(entityManager);
        return valorHoraDao.getAll();
    }

    public boolean excluir(ValorHora valorHora){
        if(valorHora.getRemessas() != null && !valorHora.getRemessas().isEmpty()){
            return false;
        }
        ValorHoraDao valorHoraDao = new ValorHoraDao(entityManager);
        valorHoraDao.remover(valorHora);
        return true;
    }

    public void cadastrar(AgendamentoBuscaSistec agendamentoBuscaSistec){
        AgendamentoBuscaSistecDao agendamentoBuscaSistecDao = new AgendamentoBuscaSistecDao(entityManager);
        agendamentoBuscaSistecDao.salvar(agendamentoBuscaSistec);
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public List<AgendamentoBuscaSistec> listarAgendamentoBuscaSistec(){
        AgendamentoBuscaSistecDao agendamentoBuscaSistecDao = new AgendamentoBuscaSistecDao(entityManager);
        return agendamentoBuscaSistecDao.getAgendamentos();
    }

    public void excluir(AgendamentoBuscaSistec agendamentoBuscaSistec){
        AgendamentoBuscaSistecDao agendamentoBuscaSistecDao = new AgendamentoBuscaSistecDao(entityManager);
        agendamentoBuscaSistecDao.remover(agendamentoBuscaSistec);
    }

    public void cadastrar(AgendamentoExportacaoZeus agendamentoExportacaoZeus){
        AgendamentoExportacaoZeusDao agendamentoExportacaoZeusDao = new AgendamentoExportacaoZeusDao(entityManager);
        agendamentoExportacaoZeusDao.salvar(agendamentoExportacaoZeus);
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
        public List<AgendamentoExportacaoZeus> listarAgendamentoExportacaoZeus(){
        AgendamentoExportacaoZeusDao agendamentoExportacaoZeusDao = new AgendamentoExportacaoZeusDao(entityManager);
        return agendamentoExportacaoZeusDao.getAgendamentos();
    }

    public void excluir(AgendamentoExportacaoZeus agendamentoExportacaoZeus){
        AgendamentoExportacaoZeusDao agendamentoExportacaoZeusDao = new AgendamentoExportacaoZeusDao(entityManager);
        agendamentoExportacaoZeusDao.remover(agendamentoExportacaoZeus);
    }

    public void cadastrar(AgendamentoImportacaoZeus agendamentoImportacaoZeus){
        AgendamentoImportacaoZeusDao agendamentoImportacaoZeusDao = new AgendamentoImportacaoZeusDao(entityManager);
        agendamentoImportacaoZeusDao.salvar(agendamentoImportacaoZeus);
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public List<AgendamentoImportacaoZeus> listarAgendamentoImportacaoZeus(){
        AgendamentoImportacaoZeusDao agendamentoImportacaoZeusDao = new AgendamentoImportacaoZeusDao(entityManager);
        return agendamentoImportacaoZeusDao.getAgendamentos();
    }

    public void excluir(AgendamentoImportacaoZeus agendamentoImportacaoZeus){
        AgendamentoImportacaoZeusDao agendamentoImportacaoZeusDao = new AgendamentoImportacaoZeusDao(entityManager);
        agendamentoImportacaoZeusDao.remover(agendamentoImportacaoZeus);
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    public ParametrosVingentes getParametrosVingentes(){
        return ParametrosUtil.getParametrosVingentes(entityManager);
    }

    public void atualizarParametrosVingentes(ParametrosVingentes parametrosVingentes){
        ParametrosVingentesDao parametrosVingentesDao = new ParametrosVingentesDao(entityManager);
        parametrosVingentes = parametrosVingentesDao.atualizar(parametrosVingentes);
    }

}

El bean administrado llama al método getParametrosVingentes () del bean de sesión. Utilizo un método estático de ParametrosUtil para obtener (si existe) o crear (si no existe) ParametrosVingentes. Es porque es necesario que solo haya un ParametrosVingentes en la aplicación. Es el bean que tiene los parámetros utilizados por otros componentes. Este es el código de ParametrosUtil:

public class ParametrosUtil {

    public static synchronized ParametrosVingentes getParametrosVingentes(EntityManager entityManager){
        ParametrosVingentesDao parametrosVingentesDao = new ParametrosVingentesDao(entityManager);
        ParametrosVingentes parametrosVingentes = parametrosVingentesDao.buscar(ParametrosVingentes.ID);
        if(parametrosVingentes == null){
            parametrosVingentes = new ParametrosVingentes();
        }
        return parametrosVingentes;
    }

    public static synchronized ParametrosVingentes atualizarParametrosVingentes(ParametrosVingentes parametrosVingentes, EntityManager entityManager){
        ParametrosVingentesDao parametrosVingentesDao = new ParametrosVingentesDao(entityManager);
        return parametrosVingentesDao.atualizar(parametrosVingentes);
    }
}

Este es el bean administrado:

@Named(value = "parametros")
@ConversationScoped
public class Parametros implements Serializable {

    public static final int VISAO_PARAMETROS_VINGENTES = 1;
    public static final int VISAO_VALOR_HORA = 2;
    public static final int VISAO_AGENDAMENTO_SISTEC = 3;
    public static final int VISAO_AGENDAMENTO_EXPORTACAO_ZEUS = 4;
    public static final int VISAO_AGENDAMENTO_IMPORTACAO_ZEUS = 5;

    private int visaoAtual;

    @EJB
    private ParametrosService parametrosService;

    @Inject
    private Conversation conversation;

    private ValorHora valorHora;
    private AgendamentoBuscaSistec agendamentoBuscaSistec;
    private AgendamentoExportacaoZeus agendamentoExportacaoZeus;
    private AgendamentoImportacaoZeus agendamentoImportacaoZeus;

    private List<ValorHora> listaValorHora;
    private boolean listaValorHoraModificada;
    private List<AgendamentoBuscaSistec> listaAgendamentoBuscaSistec;
    private boolean listaAgendamentoBuscaSistecModificada;
    private List<AgendamentoExportacaoZeus> listaAgendamentoExportacaoZeus;
    private boolean listaAgendamentoExportacaoZeusModificada;
    private List<AgendamentoImportacaoZeus> listaAgendamentoImportacaoZeus;
    private boolean listaAgendamentoImportacaoZeusModificada;

    private ParametrosVingentes parametrosVingentes;

    public Parametros() {
        this.visaoAtual = VISAO_PARAMETROS_VINGENTES;
    }

    @PostConstruct
    public void init(){
        this.conversation.begin();
        this.parametrosVingentes = this.parametrosService.getParametrosVingentes();    
    }

    public ParametrosVingentes getParametrosVingentes() {
        return parametrosVingentes;
    }

    public List<ValorHora> getListaValorHora(){
        if(this.listaValorHora == null || this.listaValorHoraModificada){
            this.listaValorHoraModificada = false;
            this.listaValorHora = this.parametrosService.listarValorHora();
        }
        return this.listaValorHora;
    }

    public List<AgendamentoBuscaSistec> getListaAgendamentoBuscaSistec(){
        if(this.listaAgendamentoBuscaSistec == null || this.listaAgendamentoBuscaSistecModificada){
            this.listaAgendamentoBuscaSistecModificada = false;
            this.listaAgendamentoBuscaSistec = this.parametrosService.listarAgendamentoBuscaSistec();
        }
        return this.listaAgendamentoBuscaSistec;
    }

    public List<AgendamentoExportacaoZeus> getListaAgendamentoExportacaoZeus(){
        if(this.listaAgendamentoExportacaoZeus == null || this.listaAgendamentoExportacaoZeusModificada){
            this.listaAgendamentoExportacaoZeusModificada = false;
            this.listaAgendamentoExportacaoZeus = this.parametrosService.listarAgendamentoExportacaoZeus();
        }
        return this.listaAgendamentoExportacaoZeus;
    }

    public List<AgendamentoImportacaoZeus> getListaAgendamentoImportacaoZeus(){
        if(listaAgendamentoImportacaoZeus == null || this.listaAgendamentoImportacaoZeusModificada){
            this.listaAgendamentoImportacaoZeusModificada = false;
            this.listaAgendamentoImportacaoZeus = this.parametrosService.listarAgendamentoImportacaoZeus();
        }
        return this.listaAgendamentoImportacaoZeus;
    }

    public void atualizarParametrosVingentes(){
        this.parametrosService.atualizarParametrosVingentes(this.parametrosVingentes);
    }

    // Other methods

Y este es el JSF:

<p:fieldset>
    <h:panelGrid columns="2">
        <h:outputLabel value="Valor da hora:" for="valorHoraVingente" />
        <p:selectOneMenu id="valorHoraVingente" value="#{parametros.parametrosVingentes.valorHora}">
            <f:selectItem itemLabel="Selecione" itemValue="#{null}" />
            <f:selectItems value="#{parametros.listaValorHora}" />
        </p:selectOneMenu>
        <h:outputLabel value="Agendamento da Busca do Sistec:" for="agendamentoBuscaSistecVingente" />
        <p:selectManyCheckbox id="agendamentoBuscaSistecVingente" value="#{parametros.parametrosVingentes.agendamentosBuscaSistec}">
            <f:selectItem itemLabel="Selecione" itemValue="#{null}" />
            <f:selectItems value="#{parametros.listaAgendamentoBuscaSistec}" />
        </p:selectManyCheckbox>
        <h:outputLabel value="Agendamento da Exportação para o Zeus:" for="agendamentoExportacaoZeusVingente" />
        <p:selectManyCheckbox id="agendamentoExportacaoZeusVingente" value="#{parametros.parametrosVingentes.agendamentosExportacaoZeus}">
            <f:selectItem itemLabel="Selecione" itemValue="#{null}" />
            <f:selectItems value="#{parametros.listaAgendamentoExportacaoZeus}" />
        </p:selectManyCheckbox>
        <h:outputLabel value="Agendamento da Importação para o Zeus:" for="agendamentoImportacaoZeusVingente" />
        <p:selectManyCheckbox id="agendamentoImportacaoZeusVingente" value="#{parametros.parametrosVingentes.agendamentosImportacaoZeus}">
            <f:selectItem itemLabel="Selecione" itemValue="#{null}" />
            <f:selectItems value="#{parametros.listaAgendamentoImportacaoZeus}" />
        </p:selectManyCheckbox>
    </h:panelGrid>
    <p:commandButton value="Atualizar" action="#{parametros.atualizarParametrosVingentes}" update="@form" />
</p:fieldset>

Como puedes ver, hay campos vinculados con las colecciones que se deben buscar con LAZY.

Y este es el seguimiento de la pila:

WARNING: failed to lazily initialize a collection, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
    at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
    at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:122)
    at org.hibernate.collection.PersistentBag.isEmpty(PersistentBag.java:255)
    at javax.faces.component.UIInput.isEmpty(UIInput.java:1257)
    at javax.faces.component.UIInput.validateValue(UIInput.java:1144)
    at javax.faces.component.UISelectMany.validateValue(UISelectMany.java:581)
    at javax.faces.component.UIInput.validate(UIInput.java:967)
    at javax.faces.component.UIInput.executeValidate(UIInput.java:1233)
    at javax.faces.component.UIInput.processValidators(UIInput.java:698)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
    at org.primefaces.component.fieldset.Fieldset.processValidators(Fieldset.java:197)
    at javax.faces.component.UIForm.processValidators(UIForm.java:253)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
    at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
    at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1172)
    at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
    at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
    at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
    at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:98)
    at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:91)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:162)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:330)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:174)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:828)
    at com.sun.grizzly.http.ProcessorTask.doProcess(ProcessorTask.java:725)
    at com.sun.grizzly.http.ProcessorTask.process(ProcessorTask.java:1019)
    at com.sun.grizzly.http.DefaultProtocolFilter.execute(DefaultProtocolFilter.java:225)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:722)

Creo que al final del método getParametrosVingentes del servicio, el EntityManager es claro y todas las entidades están separadas. ¿Podría ser el problema

Estoy ejecutando esto en Glassfish 3, usando Mojarra 2.1.2 y EJB 3.1. Gracias por cualquier ayuda

Respuestas a la pregunta(2)

Su respuesta a la pregunta