3 Replies Latest reply on Feb 17, 2010 4:35 PM by Janey Masters

    TransactionRequiredException with em as producer field

    Janey Masters Newbie

      Hey all,

      I was happy to hear that the bug -- WELD attemps to close the EntityManager Link -- has been fixed with WELD-1.0.1.CR2. So I downloaded the new version and tried again the example from WELD using a producer field for injecting the EM:

      public class LoginAction implements Serializable, ILoginActionLocal 
           private static final long serialVersionUID = 1L;
           private User user;
              @Inject Credentials credentials;
            *     inject EM
           @Inject @BankDatabase EntityManager database;     // --> only works once
           //@PersistenceContext private EntityManager database; // --> always works fine
           public void login()     {
                // logout old user
                user = (User) database.find(User.class, credentials.getUsername());
                if(user == null)
                     FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(
                               "User does not exist: " + credentials.getUsername()));
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Welcome, " 
                          + credentials.getUsername()));          
           public void register()     {
                User user = (User) database.find(User.class, credentials.getUsername());
                if(user != null)
                     FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(
                               "User already registered: " + user.getName() 
                               + ", at date: "+ user.getInsertDate()));
                } else
                     user = new User();
                     user.setInsertDate(new Date());
                     FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(
                               "Welcome, " + credentials.getUsername()));
           public void logout() {
                user = null;

      Database producer class:

      public class BankDatabaseProducer {
           @Produces @BankDatabase @PersistenceContext EntityManager userDatabase;

      The login form:

        <ui:composition template="template.xhtml">
          <ui:define name="content">
              <h:panelGrid columns="2" rendered="#{!login.loggedIn}"> 
                <h:outputLabel for="username">Username:</h:outputLabel> 
                <h:inputText id="username" value="#{credentials.username}"/> 
                <h:outputLabel for="password">Password:</h:outputLabel> 
                <h:inputText id="password" value="#{credentials.password}"/> 
              <h:commandButton value="Login" action="#{login.login}" rendered="#{!login.loggedIn}"/> 
              <h:commandButton value="Register" action="#{login.register}" rendered="#{!login.loggedIn}"/> 
              <h:commandButton value="Logout" action="#{login.logout}" rendered="#{login.loggedIn}"/> 

      If I use the EM injected by the @BankDatabase producer field, I am getting following error, when calling the register method twice (!) The first call is successfull.

      11:30:20,455 ERROR[javax.enterprise.resource.webcontainer.jsf.application] javax.ejb.EJBException: javax.persistence.TransactionRequiredException: no transaction is in progress: javax.faces.el.EvaluationException: javax.ejb.EJBException: javax.persistence.TransactionRequiredException: no transaction is in progress
           at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:102)
           at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:102)
           at javax.faces.component.UICommand.broadcast(UICommand.java:315)
           at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:775)
           at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1267)
           at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:82)
           at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)

      Using @PersistenceContext private EntityManager database; always works fine.

      Why is that? What is wrong with my code? I googled a lot and always found, that the EntityManager should care for all transactions. I also tried to use the @SessionScope annotation with the producer field, because I thought it might be destroyed to early (producer fields are scoped dependend by default). But nothing changed.

      Can you give me a hint?