16

I have a bean class with multiple (custom) inner constraints and one class-level constraint. I'd like to validate the inner constraints before the class-level constraint. The code looks like this:

@GroupSequence({ Inner.class, NewSlotBean.class })
@TotalBeanValid(groups = NewSlotBean.class)
public class NewSlotBean {

    @DayMonthYearString(groups = Inner.class)
    private String slotDay;

    @TimeString(groups = Inner.class)
    private String slotBegin;

    @LengthString(groups = Inner.class)
    private String slotLength;
}

(Inner is just an empty interface lying around somewhere).

However, when I try to run this, the class-level constraint does not get validated at all. When I try to define the GroupSequence like

@GroupSequence({ Inner.class, Outer.class })

(with Outer being a random interface), I get the exception:

javax.validation.GroupDefinitionException: ...*.beans.NewSlotBean must be part of the redefined default group sequence.

Does s/o know how to make sure that the class-level constraint is validated after the inner ones? (This appears not to be the default! I've had random problems with it popping up after a while.)

Hinton
  • 2,320
  • 4
  • 26
  • 32

1 Answers1

19

Try this:

@GroupSequence({ Inner.class, NewSlotBean.class })
@TotalBeanValid(groups = Default.class)
public class NewSlotBean {

    @DayMonthYearString(groups = Inner.class)
    private String slotDay;

    @TimeString(groups = Inner.class)
    private String slotBegin;

    @LengthString(groups = Inner.class)
    private String slotLength;
}

According to the spec NewSlotBean is just a stand-in for the default group. See also section 3.4.3 of the Bean Validation spec:

Since sequences cannot have circular dependencies, using Default in the declaration of a sequence is not an option. Constraints hosted on a class A and belonging to the Default group (by default or explicitly) implicitly belong to the group A.

A sequence defined on a class A (i.e. redefining the Default groups for the class) must contain the group A. In other words, the default constraints hosted on a class must be part of the sequence definition. If a @GroupSequence redefining the Default group for a class A does not contain the group A, a GroupDefinitionException is raised when Constraint declaration and validation process the class is validated or when its metadata is requested.

Hardy
  • 18,659
  • 3
  • 49
  • 65
  • 5
    Just an improvement suggestion to an excellent answer: it's probably better to group the validations the other way around: `@GroupSequence({ NewSlotBean.class, ClassLevel.class }) @TotalBeanValid(groups = ClassLevel.class)` on the `NewSlotBean` class and then remove the `InnerGroup` validation group and the field level group assignments - the field validations are autmatically assigned to the default validation group. Less code, cleaner. – jannis Jul 17 '17 at 10:13
  • 1
    @jannis which jar contains annotation @TotalBeanValid? Thanks – italktothewind Feb 06 '19 at 19:33
  • 1
    @italktothewind, I believe that TotalBeanValid is just a custom validation annotation. – user471011 May 25 '20 at 10:40