0 Replies Latest reply on Jul 11, 2011 6:42 AM by jsoye

    Seam-booking: Error with composite components & validator child

    jsoye

      Hi,
      In the seam-booking example, if you log in to the application, select Account and then Change Password, you correctly get errors when you click on the Change button without entering any fields. However, if you hit Change a second time, you get a java.lang.NullPointerException.


      The code looks pretty reasonable to me. You have the markup for an input component in input.xhtml, i.e.


      ...
         <cc:interface componentType="org.jboss.seam.faces.InputContainer">
            <cc:attribute name="label" required="true"/>
            <cc:attribute name="required" required="false"/>
            <cc:attribute name="ajax" required="false" default="false"/>
            <cc:attribute name="inputs" required="false" default="1"/>
         </cc:interface>
         
         <cc:implementation>
      
            <div class="entry" id="#{cc.clientId}">
               <h:outputLabel id="label" for="" value="#{cc.attrs.label}:" styleClass="#{cc.attrs.invalid ? 'label errors' : 'label'}">
                  <h:panelGroup styleClass="required" rendered="#{cc.attrs.required}">*</h:panelGroup>
               </h:outputLabel>
               <span class="#{cc.attrs.invalid ? 'input errors' : 'input'}">
                  <cc:insertChildren/>
               </span>
               <h:panelGroup rendered="#{cc.attrs.invalid}">
                  <c:forEach var="i" begin="1" end="#{cc.attrs.inputs}">
                     <h:message id="message#{i}" for="" styleClass="error errors"/>
                  </c:forEach>
               </h:panelGroup>
            </div>
      
         </cc:implementation>
      ...
      



      In the usage page, password.xhtml, we have


      ...
         <p:input id="current" label="Current password">
            <h:inputSecret id="input" value="#{currentUser.password}">
                 <f:validator validatorId="currentPassword"/>
            </h:inputSecret>
         </p:input>
      ...
      



      with the validator being declared in CurrentPasswordValidator:


      ...
      @FacesValidator("currentPassword")
      public class CurrentPasswordValidator implements Validator {
      ...
          @Inject
          @Authenticated
          private User currentUser;
      ...
          public void validate(final FacesContext ctx, final UIComponent comp, final Object value) throws ValidatorException {
              String currentPassword = (String) value;
              
              if(currentUser==null) {
                  System.out.println("--------------------->currentUser is NULL");
              } else {
                  System.out.println("--------------------->currentUser is "+currentUser.getUsername());            
              }
              if ((currentUser.getPassword() != null) && !currentUser.getPassword().equals(currentPassword)) {
                  /*
                   * FIXME: This is an ugly way to put i18n in FacesMessages: https://jira.jboss.org/browse/SEAMFACES-24
                   */            
      
                  throw new ValidatorException(new FacesMessage(messageBuilder
                          .key(new DefaultBundleKey("account_passwordsDoNotMatch")).defaults("Passwords do not match").build()
                          .getText()));
              }
          }
      
      }
      
      



      The variable currentUser, comes from


      ...
      @Stateful
      @SessionScoped
      public class CurrentUserManager {
          private User currentUser;
      
          @Produces
          @Authenticated
          @Named("currentUser")
          public User getCurrentAccount() {
              return currentUser;
          }
      
          public void onLogin(@Observes @Authenticated User user, HttpServletRequest request) {
              currentUser = user;
              // reward authenticated users with a longer session
              // default is kept short to prevent search engines from driving up # of sessions
              request.getSession().setMaxInactiveInterval(3600);
          }
      }
      



      When I hit the Change button the second time, currentUser is now null, despite it being SessionScoped and not reassigned a value, i.e.


      2011-07-11 10:59:18,828 WARN  [org.jboss.weld.integration.ejb.JBossSessionObjectReference] (http-127.0.0.1-8080-1) Cannot remove EJB, id unknown (likely because this is a no-interface view!)
      2011-07-11 10:59:22,859 INFO  [STDOUT] (http-127.0.0.1-8080-1) --------------------->currentUser is dan
      
      2011-07-11 10:59:23,437 WARN  [org.jboss.weld.integration.ejb.JBossSessionObjectReference] (http-127.0.0.1-8080-1) Cannot remove EJB, id unknown (likely because this is a no-interface view!)
      2011-07-11 10:59:26,859 INFO  [STDOUT] (http-127.0.0.1-8080-1) --------------------->currentUser is NULL
      
      2011-07-11 10:59:26,890 INFO  [org.jboss.seam.examples.booking.exceptioncontrol.GeneralExceptionHandler] (http-127.0.0.1-8080-1) Exception logged by seam-catch catcher: null
      2011-07-11 10:59:27,046 WARN  [org.jboss.weld.integration.ejb.JBossSessionObjectReference] (http-127.0.0.1-8080-1) Cannot remove EJB, id unknown (likely because this is a no-interface view!)
      



      Would anyone know why?
      PS - if I remove the composite component tags (p:input), and just have


            <h:inputSecret id="input" value="#{currentUser.password}">
                 <f:validator validatorId="currentPassword"/>
            </h:inputSecret>
      



      everything works fine.
      Cheers!