11 Replies Latest reply on Apr 18, 2006 1:20 PM by Jason Long

    Complex validation assign message to specific component.

    Jason Long Master

      I like the feature of using Hibernate Validator to validate my model before it is saved to the database, but I have not been able to assign messages to specific components to be displayed with

      <h:message for="email"/>
      


      This works fine if used with

       @NotNull
       @Length(min=1, max=50)
       private String email;
       public String getEmail() { return email; }
       public void setEmail(String email) { this.email = email; }
      


      ,but I need to do more complex validations against multiple fields in the model and validate against external resources.

      I would like for this to function the same as the annotations in that these messages will be assigned to a specific component and appear in the same place in my page as would the Hibernate Validator messages.

      What is the best way to achieve this in Seam?


        • 1. Re: Complex validation assign message to specific component.
          mark smith Newbie

          The following is from chapter 3 of the validation chapter of the hibernate docs. I see the @MyBeanConstraint and I wonder what that is. Is that a validation created for by the developer for that class to ensure not more than 45 instances of dog?

          Can we attach validations for the entire class similiar to the @MyBeanConstraint or do we use MyBeanConstraint? Would this be what you are looking for. I know I have complex validations that span multiple fields and multiple classes. Where should I put that, in controlling logic, and only field level constraints in validations.

          While the example only shows public property validation, you can also annotate fields of any kind of visibility.

          @MyBeanConstraint(max=45)
          public class Dog {
           @AssertTrue private boolean isMale;
           @NotNull protected String getName() { ... };
           ...
          }
          

          You can also annotate interfaces. Hibernate Validator will check all superclasses and interfaces extended or implemented by a given bean to read the appropriate validator annotations.

          public interface Named {
           @NotNull String getName();
           ...
          }
          
          public class Dog implements Named {
          
           @AssertTrue private boolean isMale;
          
           public String getName() { ... };
          
          }
          

          The name property will be checked for nullity when the Dog bean is validated.

          • 2. Re: Complex validation assign message to specific component.
            Jason Long Master

            Not sure if that is what I am looking for.

            What I would like to do is code my own logic in the method I use to persist the object and then add them to be displayed next to a particular field.

            Use

             @In(create = true)
             FacesMessages facesMessages;
            


            and then something like the following:

             if(checkEmailInExternalResource(email) {
             facesMessages.add(new FacesMessage("duplidate email);
             }
            

            ,but I see no way in the FacesMessages interface to specify a field the message applies to.

            I also tried
             fc.addMessage("email",new FacesMessage("duplicate email"));
            

            , but this does now work either.

            Any assistance woudl be greatly appreciated.

            • 3. Re: Complex validation assign message to specific component.
              Gavin King Master

              Unfortunately, JSF does not make it easy to do this. Look at ValidationInterceptor.addMessageToFacesContext() to see how to do it.

              What I will do for you is expose this functionality on FacesMessages.

              • 5. Re: Complex validation assign message to specific component.
                Jason Long Master

                Thank you for the prompt reply and proposed solution.

                I spent all day yesterday trying to get this to work. I figured this would be obvious and trivial like most of the other seam features.

                I guess it will be when you add this to FacesMessages.

                Thx again. :)

                • 6. Re: Complex validation assign message to specific component.
                  Gavin King Master

                  Fixed in CVS, please try it out for me. Thanks

                  • 7. Re: Complex validation assign message to specific component.
                    Jason Long Master

                    I checked out the CVS head and saw your modifications. Then I complied my project against the new seam jar and included it with my project I cannot get any messages to appear from either the annotations or using your modification as shown below. Going back to the old jar solves the problem.

                    Not even with <h:messages/>

                    @In(create=true)
                    FacesMessages facesMessages;
                    
                    ...
                    
                    facesMessages.add("nameFirst", new FacesMessage("Test Gavin's new component messages"));
                    


                    I have
                     <h:inputText value="#{member.nameFirst}" id="nameFirst" />
                     <h:message for="nameFirst"/>
                    


                    in my page.

                    1. Am I using the method properly?
                    2. If I do multiple validations and add a message for each one, how can I check the size of FacesMessages in order to decide if I should proceed or redirect back to form?



                    • 8. Re: Complex validation assign message to specific component.
                      Gavin King Master

                      Try updating again. Perhaps you got a broken checkout.

                      • 9. Re: Complex validation assign message to specific component.
                        Jason Long Master

                        That was it. That rocks. It seems to do exactly what I wanted.

                        • 10. Re: Complex validation assign message to specific component.
                          Jason Long Master

                          I have been using the component assigned messages in the following manner:

                          @IfInvalid(outcome = REDISPLAY)
                          public String create() {
                          
                           if(poCoupling.getSize().getId()==null) {
                           facesMessages.add("size", new FacesMessage("Size required"));
                           }
                          
                           if(poCoupling.getGrade().getId()==null) {
                           facesMessages.add("grade", new FacesMessage("Grade required"));
                           }
                          
                           if(!facesMessages.isEmpty()) return null;
                          
                           poCouplingDAO.makePersistent(poCoupling);
                          
                           return "nothing";
                          }
                          


                          I added the following method to FacesMessages in order to check to see if I should redisplay the form.

                          public boolean isEmpty() {
                           if(facesMessages.size()==0 && keyedFacesMessages.size()==0) {
                           return true;
                           } else {
                           return false;
                           }
                          }
                          


                          I need to check for the presence of an id in my objects because they are connected to a dropdown and if the id is null I get an org.hibernate.TransientObjectException.

                          Is there an existing way to do this? If not, how do you feel about adding this funtionality?

                          • 11. Re: Complex validation assign message to specific component.
                            Jason Long Master

                            I have been using the component assigned messages in the following manner:

                            @IfInvalid(outcome = REDISPLAY)
                            public String create() {
                            
                             if(poCoupling.getSize().getId()==null) {
                             facesMessages.add("size", new FacesMessage("Size required"));
                             }
                            
                             if(poCoupling.getGrade().getId()==null) {
                             facesMessages.add("grade", new FacesMessage("Grade required"));
                             }
                            
                             if(!facesMessages.isEmpty()) return null;
                            
                             poCouplingDAO.makePersistent(poCoupling);
                            
                             return "nothing";
                            }
                            


                            I added the following method to FacesMessages in order to check to see if I should redisplay the form.

                            public boolean isEmpty() {
                             if(facesMessages.size()==0 && keyedFacesMessages.size()==0) {
                             return true;
                             } else {
                             return false;
                             }
                            }
                            


                            I need to check for the presence of an id in my objects because they are connected to a dropdown and if the id is null I get an org.hibernate.TransientObjectException.

                            Is there an existing way to do this? If not, how do you feel about adding this funtionality?