4 Replies Latest reply on Oct 2, 2006 1:50 PM by pmuir

    Problem with injection in an jsf action listener

    cristi.ciuc

      Hi,

      I am working on a project that intends to use a lot of Seam.
      Everything worked fine until we had to refactor some of the calls from <h:commandButton id="submit" actionListener="#{...}"...> to <f:actionListener ...> and noticed that the Seam injection doesn't work anymore.

      I use Jboss 4.0.4GA and Seam 1.0.1, jsf-facelets 1.1.11, tomahawk 1.1.2

      I will attach here snippets of the relevant source code:

      First the xhtml page from where you make the call (basically you have some templates in which you have a form with buttons, and an <f:actionListener> that gets called when the user presses a button):

      [...]
      <ui:composition template="/templates/crud-page-template-formatted-input.xhtml">
      
      [...ui defines here...]
      
       <ui:define name="saveButtonParams">
       <f:actionListener type="com.nortel.emp.listener.AddRoleListener" />
       </ui:define>
      
      [...]
      
      </ui:composition>
      
      </body>
      </html>


      the jsf action listener being called:

      @Name("addRoleListener")
      @Stateful
      public class AddRoleListener implements ActionListener{
      
       @In(value = "roleManagement", create = true, required = true)
       private RoleManagementLocal roleManagement;
      
       public void processAction(ActionEvent evt) throws AbortProcessingException {
       [...]
       EmpRole role = new EmpRole();
       [...]
       roleManagement.add(role);
       [...]
       }
      
       @Create
       public void begin() {
       }
      
       /**
       * DOCUMENT ME!
       */
       @Destroy
       @Remove
       public void destroy() {
       }
      [...]
      }


      the RoleManagement bean:

      @Name("roleManagement")
      @SecurityDomain("emp-mft")
      @Stateless
      public class RoleManagementBean implements RoleManagementLocal, Serializable {
       private static final long serialVersionUID = 6125466770660833929L;
       private static final transient Logger logger = LoggerFactory.getDebugLogger(RoleManagementBean.class);
       private static SecurityDataService securityDataService = null;
       @In(value = "userManagement", create = true, required = true)
       private UserManagementLocal userManagement;
       private ResourceBundle errors = ResourceBundle.getBundle("Errors");
      
      [...]
      }


      The problem is that when roleManagement.add(role); (in AddRoleListener) is called, a null pointer exception is thrown (roleManagement is not injected, for what I can tell).

      In console I get:
      [debugLog] com.nortel.emp.listener.AppPhaseListener: afterPhase: Start RESTORE_VIEW(1)
      13:26:46,774 DEBUG [TabManager] Getting tab manager instance: 18510589
      13:26:46,775 DEBUG [TabManager] Getting tab manager instance: 18510589
      13:26:46,776 INFO [debugLog] com.nortel.emp.listener.AppPhaseListener: afterPhase: End RESTORE_VIEW(1)
      13:26:46,777 INFO [debugLog] com.nortel.emp.listener.AppPhaseListener: afterPhase: Start APPLY_REQUEST_VALUES(2)
      13:26:46,778 INFO [debugLog] com.nortel.emp.listener.AppPhaseListener: afterPhase: End APPLY_REQUEST_VALUES(2)
      13:26:46,779 INFO [debugLog] com.nortel.emp.listener.AppPhaseListener: afterPhase: Start PROCESS_VALIDATIONS(3)
      13:26:46,780 INFO [debugLog] com.nortel.emp.listener.AppPhaseListener: afterPhase: End PROCESS_VALIDATIONS(3)
      13:26:46,780 INFO [debugLog] com.nortel.emp.listener.AppPhaseListener: afterPhase: Start UPDATE_MODEL_VALUES(4)
      13:26:46,781 INFO [debugLog] com.nortel.emp.listener.AppPhaseListener: afterPhase: End UPDATE_MODEL_VALUES(4)
      13:26:46,782 INFO [debugLog] com.nortel.emp.listener.AppPhaseListener: afterPhase: Start INVOKE_APPLICATION(5)
      13:26:46,782 INFO [debugLog] com.nortel.emp.listener.AppPhaseListener: afterPhase: End INVOKE_APPLICATION(5)
      13:26:46,783 ERROR [[Faces Servlet]] Servlet.service() for servlet Faces Servlet threw exception
       java.lang.NullPointerException
       at com.nortel.emp.listener.AddRoleListener.processAction(AddRoleListener.java:55)
       at javax.faces.event.ActionEvent.processListener(ActionEvent.java:48)
       at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:484)
       at javax.faces.component.UICommand.broadcast(UICommand.java:75)
       at javax.faces.component.UIViewRoot._broadcastForPhase(UIViewRoot.java:94)
       at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:168)
       at org.apache.myfaces.lifecycle.LifecycleImpl.invokeApplication(LifecycleImpl.java:343)
       at org.apache.myfaces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:86)
       at javax.faces.webapp.FacesServlet.service(FacesServlet.java:137)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
       at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:144)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
       at org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)
       at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
       at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
       at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
       at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
       at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:175)
       at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:524)
       at org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:74)
       at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
       at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
       at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
       at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
       at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
       at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
       at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
       at org.apache.tomcat.util.net.MasterSlaveWorkerThread.run(MasterSlaveWorkerThread.java:112)
       at java.lang.Thread.run(Thread.java:595)



      Note that when using in RoleManagementBean

      @In(value = "userManagement", create = true, required = true)
       private UserManagementLocal userManagement;
      


      everything is fine.

      I am really stuck. I have tried adding interceptors annotation like

      @Interceptors(SeamInterceptor.class)
      @Intercept(InterceptionType.AFTER_RESTORE_VIEW)


      to the AddRoleListener bean (hoping to force Seam to intercept the action listener) with no result whatsoever.

      For what it seems the call to the ActionListener doesn't get intercepted by Seam. If, instead of the @In annotation, I use @EJB I still get the null pointer exception.

      So, what do I do wrong? From the Seam documentation :

      Seam even encourages you to use session beans as JSF action listeners!


      Thanks in advance,
      Cristi

        • 1. Re: Problem with injection in an jsf action listener
          pmuir

          You got the answer in your subject :)

          In your first situation you are injecting the ActionListener (#{...}) which means Seam instantiates it properly. In the second situation you are just creating a new instance

          ActionListener al = new com.nortel.emp.listener.AddRoleListener();


          - Seam doesn't instantiate it and so nothing gets injected.

          • 2. Re: Problem with injection in an jsf action listener
            gavin.king

            To "new" a Seam component use Component.getInstance(name)

            • 3. Re: Problem with injection in an jsf action listener
              cristi.ciuc

              Thank you for the replies.

              So, I understand that when

              <f:actionListener type="com.nortel.emp.listener.AddRoleListener" />


              is called, a new instance of the listener gets created, that is not intercepted by Seam. Is that correct?

              If so, my question still stands: how can I use seam injection in a JSF ActionListener? How can I tell Seam via the <f:actionListener /> tag to use an existing instance of my listener, (annotated as a seam component ) and not create a new one?

              Thx,
              Cristi



              • 4. Re: Problem with injection in an jsf action listener
                pmuir

                 

                "cristi.ciuc" wrote:
                Thank you for the replies.

                So, I understand that when

                <f:actionListener type="com.nortel.emp.listener.AddRoleListener" />


                is called, a new instance of the listener gets created, that is not intercepted by Seam. Is that correct?


                Yes, from org.apache.myfaces.taglib.core.ActionListener

                ActionListener al = (ActionListener)ClassUtils.newInstance(className);


                and ClassUtils.newInstance is basically a wrapper for Class clazz.newInstance();

                If so, my question still stands: how can I use seam injection in a JSF ActionListener? How can I tell Seam via the <f:actionListener /> tag to use an existing instance of my listener, (annotated as a seam component ) and not create a new one?


                Well AFAICS you can't with f:actionListener as it stands - you have to use the actionListener attribute on the tag.

                You could of course extend/create your own my:actionListener with, say, a value attribute, which would would then instantiate a Seam component (either via EL using the SeamVariableResolver or as Gavin mentioned above).