SimenB
SimenB

Reputation: 7489

JSR303 - Apply all validation-groups defined in sequence

I've got a bean I'd like to do conditional validation on. For this purpose, I've defined a DefaultGroupSequenceProvider<MyObject> which returns the list of groups to validate against.

Now, when validating an object that violates the constraints in more than one group in the sequence, only the first group with failures return it's result. I'd like to get an error on all violations, not just the ones in the first group with failures.

I'm thinking that this doesn't need a code-sample, but if I'm wrong, I'll be happy to provide one.

I followed this http://kh-yiu.blogspot.com/2014/04/conditional-bean-validation-using.html when creating the sequence. We use Spring if that matters.

Just a note, this works, in that it is impossible that an invalid bean will be reported as valid. But if the user has some input that breaks 3 constraints, and I return back 2 failures, the user will get another failure on the last field as soon as the first ones are corrected. Not exactly user-friendly.

Example:

Bean

@GroupSequenceProvider(BeanSequenceProvider.class)
public class MyBean {
    @NotEmpty
    private String name;

    @NotNull
    private MyType type;

    @NotEmpty(groups = Special.class)
    private String lastName;

    // Getters and setters        
}

Enum type

public enum MyType {
    FIRST, SECOND
}

Provider

public class BeanSequenceProvider implements DefaultGroupSequenceProvider<MyBean> {
    @Override
    public List<Class<?>> getValidationGroups(final MyBean object) {
        final List<Class<?>> classes = new ArrayList<>();

        classes.add(MyBean.class);

        if (object != null && object.getType() == MyType.SECOND) {
            classes.add(Special.class);
        }

        return classes;
    }

Group annotation

public interface Special {
}

Test class

public class MyBeanTest {

    private static Validator validator;

    private MyBean objectUnderTest;

    @BeforeClass
    public static void setUpOnce() throws Exception {
        final ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();

        validator = validatorFactory.getValidator();
    }

    @Before
    public void setUp() throws Exception {
        objectUnderTest = new MyBean();

        objectUnderTest.setName("Simen");
        objectUnderTest.setType(MyType.FIRST);
        objectUnderTest.setLastName("Woop");
    }

    @Test
    public void testValid() throws Exception {
        assertThat(validator.validate(objectUnderTest), is(empty()));
    }

    @Test
    public void testMissingName() throws Exception {
        objectUnderTest.setName(null);

        assertThat(validator.validate(objectUnderTest), hasSize(1));
    }

    @Test
    public void testMissingLastName() throws Exception {
        objectUnderTest.setLastName(null);

        assertThat(validator.validate(objectUnderTest), is(empty()));

        objectUnderTest.setType(MyType.SECOND);

        assertThat(validator.validate(objectUnderTest), hasSize(1));

        objectUnderTest.setName(null);

        assertThat(validator.validate(objectUnderTest), hasSize(2));
    }

That very last assert fail, as there's one violation, not 2. As the constraint is violated in the default group, the Special group is not violated.

Upvotes: 4

Views: 4473

Answers (1)

Hardy
Hardy

Reputation: 19129

Ok, now I understand your question. The answer is that validation stops if there are one or more violations within a given group. To quote the spec:

Processing a group is defined in Section 4.6, “Validation routine” ; if one of the groups processed in the sequence generates one or more constraint violations, the groups following in the sequence must not be processed. This ensures that a set of constraint is evaluated only if another set of constraint is valid.

See http://beanvalidation.org/1.1/spec/#constraintdeclarationvalidationprocess-groupsequence-groupsequence

In your case there is a violation in the Default group which means the Special group is never validated.

Upvotes: 2

Related Questions