Hibernate Validator
  1. Hibernate Validator
  2. HV-462

Allow ordered validator's annotations

    Details

    • Type: New Feature New Feature
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 4.1.0.Final
    • Fix Version/s: 5.x
    • Component/s: engine, validators
    • Labels:
      None
    • Last commented by a user?:
      true

      Description

      1) Consider domain object with simple constraints (just to demonstrate required feature, my real example uses custom cost-expensive validation of pictures):

      public class DomainObject {
      
      	@Size(max=50) // constraint 1a
      	@Pattern(regexp="[a-z]*") // constraint 1b
      	private String name;
      	
      	@Size(max=20) // constraint 2a
      	@URL // constraint 2b
      	private String email;
      	
      	@Size(max=100) // constraint 3a
      	@Pattern(regexp="[0-9]*") // constraint 3b
      	private String password;
      	
      

      2) Consider validation requirements:

      • all properties should be validated together (like one virtual group)
      • FOR EACH PROPERTY validation should occur in ordered steps given by order of annotations for given property (if first validation step fails, SKIP following validation process on given property and add validation message specific to failed / last validated constraint for the property)

      3) Why it is useful:

      • simple cost-effective validation followed by cost-expensive validation (not executed if simple constraint fails)
      • we get just the "main and specific validation error" (otherwise we have to iterate over all errors "to find the cause" or we display two or more errors for one property which is not user-friendly according my opinion)

      3) What is unusable:

      • groups and group sequences (it is not possible to create proper combination of groups and sequences for more than one property with two or more constraints)
      • composed constraints (@ReportAsSingleViolation included)
        • we cannot use @ReportAsSingleViolation since we want specific message for each failed constraint
        • and main problem is: if we use composed constraints all constraints are evaluated for given property

      4) Proposed solution:

      • add optional order attribute to validator annotations and stop validation on first failure if order is specified
      • possibly this can be configured on global validator level with property "skipOnFirstFailure" together with some given convention for annotation order

      Please let me know if need better explanation or working examples.

        Issue Links

          Activity

          Hide
          Hardy Ferentschik added a comment -

          So, how is your solution different to this:

          @GroupSequence({ Step1.class, Step2.class })
          public class DomainObject {
          	@Size(max=50, groups = Step1.class)
          	@Pattern(regexp="[a-z]*", groups = Step2.class)
          	private String name;
          	
          	@Size(max=20, groups = Step1.class)
          	@URL(groups = Step2.class)
          	private String email;
          	
          	@Size(max=100, groups = Step1.class)
          	@Pattern(regexp="[0-9]*", groups = Step2.class)
          	private String password;
          }
          
          public interface Step1 {
          }
          
          public interface Step2 {
          }
          
          Show
          Hardy Ferentschik added a comment - So, how is your solution different to this: @GroupSequence({ Step1.class, Step2.class }) public class DomainObject { @Size(max=50, groups = Step1.class) @Pattern(regexp= "[a-z]*" , groups = Step2.class) private String name; @Size(max=20, groups = Step1.class) @URL(groups = Step2.class) private String email; @Size(max=100, groups = Step1.class) @Pattern(regexp= "[0-9]*" , groups = Step2.class) private String password; } public interface Step1 { } public interface Step2 { }
          Hide
          Pavla Nováková added a comment -

          Thank you Hardy for your comment, I'll try explain better the problem on solution you suggest:

          Let's start from the result we want after web form is submitted - consider user's input and error messages that should display in form after validation:

          • name=aron5 [Only letters a-z are valid for name field.] (Constraint 1a passes, constraint 1b fails)
          • email=MyTooLongEmailOverTwentyCharacters@somemail.com [Too long email address - maximum is 20 characters.] (Constraint 2a fails, Constraint 2b should not be validated, since previous step failed)
          • password=SomePasswordWithLetters [Only numbers 0-9 are valid for password field.] (Constraint 3a passes, constraint 3b fails)

          Citation from Hibernate Validator manual:
          "If at least one constraints fails in a sequenced group none of the constraints of the following groups in the sequence get validated."

          Using, what you suggested means, that Step1 group is validated first and it fails on email property and so Step2 group validation is skipped. The result you get is:

          • name=aron5 [MISSING ERROR MESSAGE]
          • email=MyTooLongEmailOverTwentyCharacters@somemail.com [Too long email address - maximum is 20 characters.] (correct)
          • password=SomePasswordWithLetters [MISSING ERROR MESSAGE]

          I hope I was clear enough and it does make sense.

          Show
          Pavla Nováková added a comment - Thank you Hardy for your comment, I'll try explain better the problem on solution you suggest: Let's start from the result we want after web form is submitted - consider user's input and error messages that should display in form after validation: name=aron5 [Only letters a-z are valid for name field.] (Constraint 1a passes, constraint 1b fails) email=MyTooLongEmailOverTwentyCharacters@somemail.com [Too long email address - maximum is 20 characters.] (Constraint 2a fails, Constraint 2b should not be validated, since previous step failed) password=SomePasswordWithLetters [Only numbers 0-9 are valid for password field.] (Constraint 3a passes, constraint 3b fails) Citation from Hibernate Validator manual: "If at least one constraints fails in a sequenced group none of the constraints of the following groups in the sequence get validated." Using, what you suggested means, that Step1 group is validated first and it fails on email property and so Step2 group validation is skipped. The result you get is: name=aron5 [MISSING ERROR MESSAGE] email=MyTooLongEmailOverTwentyCharacters@somemail.com [Too long email address - maximum is 20 characters.] (correct) password=SomePasswordWithLetters [MISSING ERROR MESSAGE] I hope I was clear enough and it does make sense.
          Hide
          Hardy Ferentschik added a comment -

          I see where you are coming from. I still it is possible with the current approach, but cumbersome:

          public class DomainObject {
          	@Size(max=50, groups = NameStep1.class)
          	@Pattern(regexp="[a-z]*", groups = NameStep2.class)
          	private String name;
          	
          	@Size(max=20, groups = EmailStep1.class)
          	@URL(groups = EmailStep2.class)
          	private String email;
          
          }
          
          @GroupSequence({ NameStep1.class, NameStep2.class })
          public interface NameSequence{
          }
          
          public interface NameStep1 {
          }
          
          public interface NameStep2 {
          }
          
          @GroupSequence({ EmailStep1.class, EmailStep2.class })
          public interface EmailSequence{
          }
          
          public interface EmailStep1 {
          }
          
          public interface EmailStep2 {
          }
          

          At validation time you would then validate the groups NameSequence and EmailSequence.
          Obviously

          validation should occur in ordered steps given by order of annotations for given property

          is not possible, because there is no way to introspect the order of annotations for a given property. Leaves the order which is really a change the Bean Validation spec and should be discussed there. I wonder how such an attribute would then tie in with the current group and group sequence mechanism?

          Show
          Hardy Ferentschik added a comment - I see where you are coming from. I still it is possible with the current approach, but cumbersome: public class DomainObject { @Size(max=50, groups = NameStep1.class) @Pattern(regexp= "[a-z]*" , groups = NameStep2.class) private String name; @Size(max=20, groups = EmailStep1.class) @URL(groups = EmailStep2.class) private String email; } @GroupSequence({ NameStep1.class, NameStep2.class }) public interface NameSequence{ } public interface NameStep1 { } public interface NameStep2 { } @GroupSequence({ EmailStep1.class, EmailStep2.class }) public interface EmailSequence{ } public interface EmailStep1 { } public interface EmailStep2 { } At validation time you would then validate the groups NameSequence and EmailSequence . Obviously validation should occur in ordered steps given by order of annotations for given property is not possible, because there is no way to introspect the order of annotations for a given property. Leaves the order which is really a change the Bean Validation spec and should be discussed there. I wonder how such an attribute would then tie in with the current group and group sequence mechanism?
          Hide
          Hardy Ferentschik added a comment -

          This can really only be addressed from the spec - BVAL-248

          Show
          Hardy Ferentschik added a comment - This can really only be addressed from the spec - BVAL-248
          Hide
          Emmanuel Bernard added a comment -

          An advanced discussion took place at http://beanvalidation.org/proposals/BVAL-248/
          I think we should try and experiment with HV before spec'ing it

          Show
          Emmanuel Bernard added a comment - An advanced discussion took place at http://beanvalidation.org/proposals/BVAL-248/ I think we should try and experiment with HV before spec'ing it

            People

            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:

                Development