8 Replies Latest reply on Nov 2, 2012 6:21 AM by nickarls

    Bug with validation or rendering after validation failure (?)

    jmsjr

      Environment:

       

      JBoss 7.1.1 (Brontes)

      JDK 1.7.0_06 32-bit

      Win7 64-bit

       

       

      {code}

      17:40:44,365 INFO  [javax.enterprise.resource.webcontainer.jsf.config] (MSC service thread 1-13) Initializing Mojarra 2.1.7-jbossorg-1 (20120227-1401)

      {code}

       

       

      Below is the very simple test case:

       

       

       

       

      1) A very simple request-scoped bean:

       

       

      {code}

      package test;

       

       

      import java.io.Serializable;

       

       

      import javax.faces.bean.ManagedBean;

      import javax.faces.bean.RequestScoped;

      import javax.validation.constraints.NotNull;

       

       

      @ManagedBean

      @RequestScoped

      public class RequestBean implements Serializable {

       

        private static final long serialVersionUID = 1L;

       

       

        @NotNull(message="Input 1 is required")

        private String input1;

       

        @NotNull(message="Input 2 is required")

        private String input2;

       

        public String getInput1() {

        return input1;

        }

       

        public String getInput2() {

        return input2;

        }

       

        public void setInput1(String input1) {

        this.input1 = input1;

        }

       

        public void setInput2(String input2) {

        this.input2 = input2;

        }

       

       

      }

      {code}

       

       

       

      2) A very simple test.xhtml page:

       

       

      {code}

      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

      <html xmlns="http://www.w3.org/1999/xhtml"

            xmlns:h="http://java.sun.com/jsf/html"

            xmlns:f="http://java.sun.com/jsf/core"

            xmlns:ui="http://java.sun.com/jsf/facelets">

       

       

      <h:head></h:head>

      <body>

       

       

      <h:form>

       

       

             <h:panelGrid columns="2">

                 Input 1: <h:inputText value="#{requestBean.input1}" />

                 Input 2: <h:inputText value="#{requestBean.input2}" />

                 <h:commandButton id="submit" value="Submit"/><br/>

                 <h:messages/><br/>

             </h:panelGrid>

      </h:form>

       

       

      </body>

      </html>

      {code}

       

       

       

      3. web.xml contents:

       

       

      {code}

      <?xml version="1.0"?>

      <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"

      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">

      <display-name>test</display-name>

        <context-param>

        <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>

        <param-value>true</param-value>

      </context-param>

        <context-param>

        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>

        <param-value>client</param-value>

      </context-param>

      <!--

        <welcome-file-list>

          <welcome-file>index.html</welcome-file>

        </welcome-file-list>

      -->

      <servlet>

        <servlet-name>Faces Servlet</servlet-name>

        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>

        <load-on-startup>1</load-on-startup>

      </servlet>

      <servlet-mapping>

        <servlet-name>Faces Servlet</servlet-name>

        <url-pattern>*.jsf</url-pattern>

      </servlet-mapping>

      <servlet-mapping>

        <servlet-name>Faces Servlet</servlet-name>

        <url-pattern>*.faces</url-pattern>

      </servlet-mapping>

      <servlet-mapping>

        <servlet-name>Faces Servlet</servlet-name>

        <url-pattern>/faces/*</url-pattern>

      </servlet-mapping>

      </web-app>

      {code}

       

       

       

       

      4. faces-config.xml contents:

       

       

      {code}

      <?xml version="1.0" encoding="UTF-8"?>

       

       

      <faces-config

          xmlns="http://java.sun.com/xml/ns/javaee"

        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_1.xsd"

        version="2.1">

       

       

      </faces-config>

      {code}

       

       

       

       

      5. Contents of WEB-INF/lib:

       

       

      {code}

      salvojo@AAS-AUD20901BL /cygdrive/c/jboss-as-7.1.1.Final/standalone

      $ ls -alt deployments/test.war/WEB-INF/lib/

      total 1384

      drwx------+ 1 Administrators Domain Users      0 Nov  2 17:40 ..

      drwx------+ 1 Administrators Domain Users      0 Nov  2 16:56 .

      -rwx------+ 1 Administrators Domain Users 393259 Nov  2 16:56 standard.jar

      -rwx------+ 1 Administrators Domain Users  21029 Nov  2 16:56 jstl.jar

      -rwx------+ 1 Administrators Domain Users  38015 Nov  2 16:56 commons-logging.jar

      -rwx------+ 1 Administrators Domain Users 139966 Nov  2 16:56 commons-digester.jar

      -rwx------+ 1 Administrators Domain Users 559366 Nov  2 16:56 commons-collections.jar

      -rwx------+ 1 Administrators Domain Users 188671 Nov  2 16:56 commons-beanutils.jar

      -rwx------+ 1 Administrators Domain Users  48742 Nov  2 16:56 common-annotations.jar

      {code}

       

       

       

       

      6. The test case

       

       

      6.1 Open the test.jsf page with your browser

       

      6.2 Click on Submit WITHOUT specifying any values for both Input1 and Input2.

       

      Expected behaviour: Messages displayed that both input fields are required.

      Actual: As expected

       

       

      6.3 Supply values for both Input1 and Input2, then click Submit

       

      Expected behaviour: No validation messages displayed. Entered values remain in the input field

      Actual: As expected

       

       

      6.4 Remove input value for Input1, then click Submit

       

       

      Expected behaviour:

      Validation message that Input1 is required.

      Current value for Input1 remain blank.

      Previous value for Input2 remain in the input field.

       

       

      Actual: As expected

       

       

      6.5 Remove input value for Input2, then click Submit ( both Input fields are now blank )

       

       

      Expected behaviour:

      Validation message both input fields are required.

      Input value for Input1 remain blank.

      Input value for Input2 remain blank.

       

       

      Actual ( NOT AS EXPECTED, see below )

       

       

      Validation message both input fields are required.

      Input value for Input1 remain blank.

      Input value for Input2 remain NON-blank. The previous value before it was blanked out and submitted is rendered / displayed on the page

        • 1. Re: Bug with validation or rendering after validation failure (?)
          nickarls

          Not really an AS question but...

           

          Isn't that what's to be expected? In JSF, the validation phase comes before the apply values phase so it "rolls back". If I didn't misunderstand something.

          • 2. Re: Bug with validation or rendering after validation failure (?)
            jmsjr

            Nicklas Karlsson wrote:

             

            Not really an AS question but...

             

            Isn't that what's to be expected? In JSF, the validation phase comes before the apply values phase so it "rolls back". If I didn't misunderstand something.

             

            Even for RequestScoped beans ? Even if that is true, then Step 6.4 in the test case should be:

             

            • Validation message that Input1 is required
            • Current value for Input1 is RESTORED to the previous value ( but as you see above, in Step 6.4, Input1 remains blanked out )
            • Previous value for Input2 remain in the input field

             

            Either way, either 6.4 or 6.5 shows a bug because:

             

            • In 6.4, the previous value was NOT restored
            • In 6.5, the previous value was restored
            • 3. Re: Bug with validation or rendering after validation failure (?)
              nickarls

              Put in the getters

               

               

              System.out.println(String.format("Getting input1 '%s'", input1));
              

               

              and in the setters

               

               

              System.out.println(String.format("Setting input1 '%s'", input1));
              

               

              and see if the lifecycle makes sense. The setters should only be called for input that passes validation.

              • 4. Re: Bug with validation or rendering after validation failure (?)
                jmsjr

                Nicklas Karlsson wrote:

                 

                Put in the getters

                 

                 

                System.out.println(String.format("Getting input1 '%s'", input1));
                

                 

                and in the setters

                 

                 

                System.out.println(String.format("Setting input1 '%s'", input1));
                

                 

                and see if the lifecycle makes sense. The setters should only be called for input that passes validation.

                 

                 

                I have now added as you suggested ( plus a few more below )

                 

                 

                {code}

                package test;

                 

                 

                import java.io.Serializable;

                import java.util.logging.Level;

                import java.util.logging.Logger;

                 

                 

                import javax.faces.bean.ManagedBean;

                import javax.faces.bean.RequestScoped;

                import javax.validation.constraints.NotNull;

                 

                 

                @ManagedBean

                @RequestScoped

                public class RequestBean implements Serializable {

                 

                          private static Logger logger = Logger.getLogger(RequestBean.class.getName());

                 

                          private static final long serialVersionUID = 1L;

                 

                 

                          @NotNull(message="Input 1 is required")

                          private String input1;

                 

                          @NotNull(message="Input 2 is required")

                          private String input2;

                 

                          public String getInput1() {

                                    logger.log(Level.INFO, "Getting input1 " + input1);

                                    return input1;

                          }

                 

                          public String getInput2() {

                                    logger.log(Level.INFO, "Getting input2 " + input2);

                                    return input2;

                          }

                 

                          public void setInput1(String input1) {

                                    logger.log(Level.INFO, "Setting input1 " + input1);

                                    this.input1 = input1;

                          }

                 

                          public void setInput2(String input2) {

                                    logger.log(Level.INFO, "Setting input2 " + input2);

                                    this.input2 = input2;

                          }

                 

                 

                }

                 

                {code}

                 

                 

                I have now added a PhaseListener that listens on all phases

                 

                 

                {code}

                package test;

                 

                 

                import java.util.logging.Level;

                import java.util.logging.Logger;

                 

                 

                import javax.faces.event.PhaseEvent;

                import javax.faces.event.PhaseId;

                import javax.faces.event.PhaseListener;

                 

                 

                /**

                * PhaseTracker for the purpose of debugging    

                *

                * @author salvojo

                */

                public class PhaseTracker implements PhaseListener {

                 

                 

                          private static final long serialVersionUID = 1L;

                          private static Logger logger = Logger.getLogger(PhaseTracker.class.getName());

                 

                 

                          @Override

                          public void beforePhase(PhaseEvent event) {

                                    logger.log( Level.INFO, "Before Phase: " + event.getPhaseId() );

                          }

                 

                 

                          @Override

                          public void afterPhase(PhaseEvent event) {

                                    logger.log( Level.INFO, "After Phase: " + event.getPhaseId() );

                          }

                 

                 

                          @Override

                          public PhaseId getPhaseId() {

                                    return PhaseId.ANY_PHASE;

                          }

                 

                 

                }

                 

                {code}

                 

                Registered it in faces-config.xml

                 

                 

                {code}

                <?xml version="1.0" encoding="UTF-8"?>

                 

                 

                <faces-config

                    xmlns="http://java.sun.com/xml/ns/javaee"

                          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

                          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_1.xsd"

                          version="2.1">

                <lifecycle>

                  <phase-listener>test.PhaseTracker</phase-listener>

                </lifecycle>

                </faces-config>

                {code}

                 

                 

                 

                Here are the results from repeating the same Steps of the test case ( output from server.log of JBoss ):

                 

                 

                {code}

                 

                6.1 Open the test.jsf page with your browser


                19:00:16,750 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: RESTORE_VIEW 1

                19:00:16,755 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: RESTORE_VIEW 1

                19:00:16,757 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: RENDER_RESPONSE 6

                19:00:16,764 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Getting input1 null

                19:00:16,765 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Getting input2 null

                19:00:16,767 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: RENDER_RESPONSE 6

                 

                 

                6.2 Click on Submit WITHOUT specifying any values for both Input1 and Input2.

                 

                 

                 

                19:00:30,821 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: RESTORE_VIEW 1

                19:00:30,824 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: RESTORE_VIEW 1

                19:00:30,826 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: APPLY_REQUEST_VALUES 2

                19:00:30,828 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: APPLY_REQUEST_VALUES 2

                19:00:30,830 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: PROCESS_VALIDATIONS 3

                19:00:30,838 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: PROCESS_VALIDATIONS 3

                19:00:30,840 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: RENDER_RESPONSE 6

                19:00:30,842 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Getting input1 null

                19:00:30,843 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Getting input2 null

                19:00:30,845 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: RENDER_RESPONSE 6

                 

                 

                6.3 Supply values for both Input1 and Input2, then click Submit

                 

                 

                 

                19:00:41,789 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: RESTORE_VIEW 1

                19:00:41,793 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: RESTORE_VIEW 1

                19:00:41,795 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: APPLY_REQUEST_VALUES 2

                19:00:41,796 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: APPLY_REQUEST_VALUES 2

                19:00:41,798 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: PROCESS_VALIDATIONS 3

                19:00:41,799 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Getting input1 null

                19:00:41,801 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Getting input2 null

                19:00:41,802 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: PROCESS_VALIDATIONS 3

                19:00:41,803 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: UPDATE_MODEL_VALUES 4

                19:00:41,804 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Setting input1 aaa

                19:00:41,806 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Setting input2 bbb

                19:00:41,807 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: UPDATE_MODEL_VALUES 4

                19:00:41,808 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: INVOKE_APPLICATION 5

                19:00:41,809 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: INVOKE_APPLICATION 5

                19:00:41,811 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: RENDER_RESPONSE 6

                19:00:41,812 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Getting input1 aaa

                19:00:41,814 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Getting input2 bbb

                19:00:41,816 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: RENDER_RESPONSE 6

                 

                 

                6.4 Remove input value for Input1, then click Submit

                 

                 

                 

                19:00:57,133 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: RESTORE_VIEW 1

                19:00:57,138 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: RESTORE_VIEW 1

                19:00:57,140 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: APPLY_REQUEST_VALUES 2

                19:00:57,141 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: APPLY_REQUEST_VALUES 2

                19:00:57,143 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: PROCESS_VALIDATIONS 3

                19:00:57,145 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Getting input2 null

                19:00:57,146 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: PROCESS_VALIDATIONS 3

                19:00:57,147 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: RENDER_RESPONSE 6

                19:00:57,149 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Getting input1 null

                19:00:57,151 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: RENDER_RESPONSE 6

                 

                 

                 

                6.5 Remove input value for Input2, then click Submit ( both Input fields are now blank )

                 

                 

                19:01:34,727 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: RESTORE_VIEW 1

                19:01:34,731 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: RESTORE_VIEW 1

                19:01:34,733 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: APPLY_REQUEST_VALUES 2

                19:01:34,735 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: APPLY_REQUEST_VALUES 2

                19:01:34,737 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: PROCESS_VALIDATIONS 3

                19:01:34,739 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: PROCESS_VALIDATIONS 3

                19:01:34,740 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) Before Phase: RENDER_RESPONSE 6

                19:01:34,742 INFO  [test.RequestBean] (http--0.0.0.0-8081-5) Getting input1 null

                19:01:34,744 INFO  [test.PhaseTracker] (http--0.0.0.0-8081-5) After Phase: RENDER_RESPONSE 6

                 

                 

                {code}

                • 5. Re: Bug with validation or rendering after validation failure (?)
                  nickarls
                  1 of 1 people found this helpful
                  • 6. Re: Bug with validation or rendering after validation failure (?)
                    jmsjr

                    Nicklas Karlsson wrote:

                     

                    Related to this?

                     

                    http://stackoverflow.com/questions/3933786/jsf-2-bean-validation-validation-failed-empty-values-are-replaced-with-las

                     

                    Yes .. That is it. So it is a bug in Mojarra itself, which has not been fixed

                     

                    http://java.net/jira/browse/JAVASERVERFACES-2262

                     

                    ... as it appears to require a spec change / clarification:

                     

                    http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-939

                     

                     

                    So the workaround is:

                     

                    1) In web.xml, set javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL to false

                    2) Do not rely on the @NotNull annotation anymore, as the submitted value is now not null, but an empty string

                    3) Add the required="true" attribute to the h:inputText field, and have the message defined in there. A PITA, but at least it works.

                    • 7. Re: Bug with validation or rendering after validation failure (?)
                      jmsjr

                      jmsjr wrote:

                       

                      Nicklas Karlsson wrote:

                       

                      Related to this?

                       

                      http://stackoverflow.com/questions/3933786/jsf-2-bean-validation-validation-failed-empty-values-are-replaced-with-las

                       

                      Yes .. That is it. So it is a bug in Mojarra itself, which has not been fixed

                       

                      http://java.net/jira/browse/JAVASERVERFACES-2262

                       

                      ... as it appears to require a spec change / clarification:

                       

                      http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-939

                       

                       

                      So the workaround is:

                       

                      1) In web.xml, set javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL to false

                      2) Do not rely on the @NotNull annotation anymore, as the submitted value is now not null, but an empty string

                      3) Add the required="true" attribute to the h:inputText field, and have the message defined in there. A PITA, but at least it works.

                       

                      Continuing on with the workaround mentioned above, I have stumbled ( again ? ) on a different bug:

                       

                      1. Modified the XHTML page as follows:

                       

                      {code}

                      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

                      <html xmlns="http://www.w3.org/1999/xhtml"

                            xmlns:h="http://java.sun.com/jsf/html"

                            xmlns:f="http://java.sun.com/jsf/core"

                            xmlns:ui="http://java.sun.com/jsf/facelets">

                       

                       

                      <h:head></h:head>

                      <body>

                       

                       

                      <h:form>

                       

                       

                             <h:panelGrid columns="6">

                                 Input 1: <h:inputText required="true" value="#{requestBean.input1}" />

                                 Current Value (as outputText): <h:outputText value="#{requestBean.input1}" />

                                 Current Value (as disabled inputText): <h:inputText disabled="true" value="#{requestBean.input1}" />

                       

                                 Input 2: <h:inputText required="true" value="#{requestBean.input2}" />

                                 Current Value (as outputText): <h:outputText value="#{requestBean.input2}" />

                                 Current Value (as disabled inputText): <h:inputText disabled="true" value="#{requestBean.input2}" />

                                 <h:commandButton id="submit" value="Submit"/><br/>

                                 <h:messages/><br/>

                             </h:panelGrid>

                      </h:form>

                       

                       

                      </body>

                      </html>

                       

                      {code}

                       

                       

                      2. Repeat the steps in the test case

                       

                      3. When you reach step 6.4 of the test case:

                       

                      • The value for Input2 is shown based on the previous value.
                      • However, the outputText and the disabled inputText for the SAME property ( input2 ) of the bean shows blank!! It's the same EL expression for all three UI components, one shows the value, two shows blank.
                      • 8. Re: Bug with validation or rendering after validation failure (?)
                        nickarls

                        Hard to tell - it's getting more and more a specific JSF question better suited for other forums (perhaps https://forums.oracle.com/forums/forum.jspa?forumID=982).

                        It could be something with different backing component implementations of the actual components in the different cases(?)

                         

                         

                        ...which you apparently already have.

                         

                        Message was edited by: Nicklas Karlsson