4

J'ai un bean géré CDI (un bean annoté avec @Named qui est utilisé sur JSF) qui a un bean Session Stateful injecté. Ce bean session est comme un service, il a le gestionnaire d'entités (annoté avec @PersistenceContext (type = PersistenceContextType.EXTENDED)) et expose des méthodes pour manipuler certaines entités. Ces entités sont sur le bean géré, ConversationScoped. Ensuite, le JSF appelle une méthode du bean géré et le bean géré appelle une méthode du "service" (le bean de session avec état). Je ne sais pas si c'est le meilleur design, mais ça marchait bien. Mais il y a une entité qui a des collections qui doivent être récupérées avec LAZY. Et la première fois que j'ouvre la page, il semble bien fonctionner, mais quand j'essaie de cliquer sur n'importe quel bouton ou de faire n'importe quelle action, j'ai l'exception LazyInitializationException. Quelqu'un a un conseil? Je ne sais pas s'il y a quelque chose qui ne va pas. Je mets le bean session comme stateful et le contexte de persistance étendu. Ce bean session est injecté dans le bean géré, qui a les entités. Pourquoi lance-t-il cette exception? Comment le gestionnaire d'entité pourrait-il être fermé?LazyInitializationException avec le bean géré CDI et le bean session avec état

C'est le code de l'entité qui est en difficulté:

@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... 

C'est la Stateful Session Bean:

@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); 
    } 

} 

Le bean géré appelle la méthode getParametrosVingentes() de la fève de la session . J'utilise une méthode statique du ParametrosUtil pour obtenir (si elle existe) ou créer (si elle n'existe pas) les ParametrosVingentes. C'est parce qu'il est nécessaire qu'il n'y ait qu'un seul ParametrosVingentes dans l'application. C'est le bean qui a les paramètres utilisés par d'autres composants. Voici le code 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); 
    } 
} 

C'est le bean géré:

@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 

Et voici le 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> 

Comme vous pouvez le voir, il y a des champs se lient avec les collections qui doivent être récupérées avec LAZY.

Et ceci est la trace de la pile:

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) 

Je pense qu'à la fin de la méthode getParametrosVingentes du service, la EntityManager est claire et toutes les entités sont détachés. Serait-ce le problème? Je l'utilise sur Glassfish 3, en utilisant Mojarra 2.1.2 et EJB 3.1. Merci pour toute aide.

+0

Je pense que quelques-uns des « autres méthodes » de 'Parametros' sont importants ici, en particulier' atualizarParametrosVingentes'. Aussi, puisque l'erreur est lors de la validation d'un select, le code qui gère la liste des options ('listaValorHora', etc.) peut être important. Enfin, soyez prudent lorsque vous commencez votre conversation. Voir http://stackoverflow.com/questions/8552478/conversation-not-propagated-automatically-on-form-submission. – Brian

+0

@Brian J'ai posté le code que vous avez demandé. J'ai débogué le bean géré, et il appelle simplement la méthode init (annotée avec PostContruct, où la conversation commence) une fois. Et la conversation semble être ok. Mais quand j'ai essayé de gérer moi-même l'EntityManager, les mêmes erreurs se sont produites. J'ai également testé le SessionBean pour voir s'il ne sauvegardait pas l'état, mais c'était le cas. Ensuite, je ne sais pas quel peut être le problème. –

Répondre

19

Eh bien, j'ai enfin résolu le problème! J'ai vu que LazyInitializationException était dans la phase de validation de selectManyCheckbox. Puis j'ai commencé à chercher ceci et ai trouvé ce lien: http://old.nabble.com/-jira---Created--(MYFACES-3306)-%3Ch%3AselectManyCheckBox%3E-%2B-JPA-with-Hibernate-creates-Hibernate-PersistentCollection-where-it-should-not.-Causes-td32463262.html

Le problème était que le JSF essayait d'employer le PersistentBag créé par le Hibernate, mais il ne l'utiliserait pas. La solution a été mise un atributte disant le JSF pour employer un ArrayList au lieu du PersistentBag.

Il peut être fait en ajoutant ceci à l'intérieur du selectManyCheckbox:

<f:attribute name="collectionType" value="java.util.ArrayList" /> 
+1

merci :-) m'a beaucoup aidé – ke3pup

+0

De rien. :) –

Questions connexes