I am using hibernate-validator-4.3.1 and am experiencing some behavior that does not seem right to me. I have a parent class that defines a @GroupSequence on the class to run the Default group then ExpensiveGroup. The parent has several constraints for ExpensiveGroup and a constraint for Default. The child has a constraint for default group.
I am seeing validation performed in this order:
1) Default group is validated on Parent;
2) ExpensiveGroup is validated on Parent;
3) Default group is validated on Child;
I was expecting the first group in the GroupSequence (Default) to be evaluated on all associated objects before the second group (ExpensiveGroup) is evaluated.
Please advise me if this is a misunderstanding on my part or a defect in the validator implementation.
Code:
@SampleConstraint(groups=ExpensiveGroup.class)
@GroupSequence({Parent.class, ExpensiveGroup.class})
public static class Parent {
public interface ExpensiveGroup {};
@SampleConstraint
public String parentDefaultGroup;
@SampleConstraint(groups=ExpensiveGroup.class)
public String parentExpensiveGroup;
@Valid
public Child child;
}
public static class Child {
@SampleConstraint
public String childDefaultGroup;
}
@Documented
@Constraint(validatedBy = {SampleConstraint.ClassValidator.class, SampleConstraint.StringValidator.class})
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SampleConstraint {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
public class ClassValidator implements ConstraintValidator<SampleConstraint, Parent> {
@Override
public void initialize(SampleConstraint constraintAnnotation) {}
@Override
public boolean isValid(Parent value,
ConstraintValidatorContext context) {
System.out.println("Class"); // print "Class"
return false;
}
}
public class StringValidator implements ConstraintValidator<SampleConstraint, String> {
@Override
public void initialize(SampleConstraint constraintAnnotation) {}
@Override
public boolean isValid(String value,
ConstraintValidatorContext context) {
System.out.println(value); // print the String value
return value.length() > 2;
}
}
}
I exercised this code with the following JUnit:
Code:
@Test
public void testCascade() throws AnixterValidationException {
Parent parent = new Parent();
parent.parentDefaultGroup = "parentDefault";
parent.parentExpensiveGroup = "parentExpensive";
Child child = new Child();
child.childDefaultGroup = "childDefault";
parent.child = child;
validator.validate(parent);
}
.. and got this output:
parentDefault
parentExpensive
Class
childDefaultNotice that *all* constraints were exercised on the parent, regardless of group, prior to any constraints running on the child.
I expected this:
parentDefault
childDefault
.. then in no particular order:
parentExpensive
Class