6 Replies Latest reply on Jun 24, 2011 2:24 PM by joshbrookes

    Problems with rich:graphValidator and Iterable Object Graph properties

    joshbrookes

      I am experiencing a roadblock when using rich:graphValidator with an object that has an object graph with Iterable properties to be validated. When the object and it's iterable property are rendered in a facelet using either ui:repeat or a4j:repeat, the data is displayed properly, but upon submitting a form with the graphValidator tag, the validation for the Iterable property always validates against empty copies of the Iterable object - it does not validate the values entered in the form - only when the Iterable object class has constraints on the class level.  It works fine if the constraints are on properties in the Iterable object class. The implementation of Cloneable appears to have no impact.

       

      Here is an example of the issue.  Suppose we have a Survey object and in it a List of Question objects.

       

      {code}

      import javax.validation.Valid;

      import org.hibernate.validator.constraints.NotBlank;

      ...

       

      public class Survey implements Serializable {

       

           private String name;

           @NotBlank(message = "Recipient is required.")

           private String recipient;

           @Valid

           private List<Question> questions;

       

           public String getName() { return name; }

       

           public void setName(String name) { this.name = name; }

       

           public String getRecipient() { return recipient; }

       

           public void setRecipient(String recipient) { this.recipient= recipient; }

       

          public List<Question> getQuestions() {

              return questions;

          }

       

          public void setQuestions(List<Question> questions) {

              this.questions= questions;

          }

       

      }

      {code}

       

       

      {code}

      import org.hibernate.validator.constraints.ScriptAssert;

      ...

       

      @ScriptAssert(lang = "javascript",

            script = "!_this.required || (_this.required && _this.answer != null && _this.answer != '')",

            message = "Answer is required.")

      public class Question implements Serializable {

       

           private String question;

           private String answer;

           private boolean required = true;

       

          public String getQuestion() {

              return question;

          }

       

          public void setQuestion(String question) {

              this.question = question;

          }

       

          public String getAnswer() {

              return answer;

          }

       

          public void setAnswer(String answer) {

              this.answer = answer;

          }

       

          public boolean isRequired() {

              return required;

          }

       

          public void setRequired(boolean required) {

              this.required = required;

          }

       

      }

      {code}

       

      Now in a facelet we have a form that has a graphValidator and a ui:repeat for the questions. Assume the Managed Bean is called SurveyBean, is of a proper scope, and contains a Survey object property called "survey" with getter and setter. Let's also assume that the Questions were grabbed from the database so that there are values in the question and required fields and the answer fields are null.

       

      {code}

      <div>

           <rich:messages />

      </div>

      <h:form>

          <rich:graphValidator value="#{surveyBean.survey}" groups="javax.validation.groups.Default" >

          <div>

               <h:commandButton value="Save" action="#{surveyBean.save}" />

          </div>

           <div>

                Survey Name: <h:outputText value="#{surveyBean.survey.name}" />

           </div>

           <div>

                Recipient: <h:inputText value="#{surveyBean.survey.recipient}" />

           </div>

           <div>

                  <ui:repeat value="#{surveyBean.survey.questions}" var="question">               

                        <h:outputText value="#{question.question}" /> <h:outputTest value="(* required)" rendered="#{question.required}" />                 

                        <div >

                          <h:inputTextarea value="#{question.answer}" />                   

                        </div>            

                  </ui:repeat>

           </div>

        </rich:graphValidator>

      </h:form>

      {code}

       

      The form validation will correctly validate the recipient property, but the questions will fail validation if the required attribute is true and the original state of the answer field is null or blank, because the Question objects get validated using whatever was the original state of the object when it was rendered (e.g., if it was loaded from the database with populated values then it may pass validation).

       

      Has anybody else seen this issue? This looks like a graphValidator bug. Without the graphValidator tags the form submits without issue but of course does not validate. I have seen this problem also with deeper nested object graphs containing Iterable properties.

       

      Any help is greatly appreciated!

       

      Regards,

      Josh