Robert van der Spek
Robert van der Spek

Reputation: 1207

Multiple constraints spring validation

I am using spring to validate a form. The model for the form is similar to this:

public class FormModel {

    @NotBlank
    private String name;

    @NotNull
    @ImageSizeConstraint
    private MultipartFile image;

}

The '@ImageSizeConstraint' is a custom constraint. What I want is for the @NotNull to be evaluated first and if this evaluates to false, not to evaluate @ImageSizeConstraint.

If this is not possible, I will have to check for null in the custom constraint as well. Which is not a problem, but I would like to seperate the concerns (not null / image size / image / aspectratio / etc).

Upvotes: 6

Views: 7292

Answers (2)

Yoann CAPLAIN
Yoann CAPLAIN

Reputation: 121

Easy just return true for isValid if image is null for your custom constraint. Read the specification of JSR-303, you will see that this is normal behaviour and it makes sense as there is "NotNull".

Upvotes: 3

Anatoly Shamov
Anatoly Shamov

Reputation: 2686

You may use constraints grouping and group sequences to define the validation order. According to JSR-303 (part 3.5. Validation routine):

Unless ordered by group sequences, groups can be validated in no particular order. This implies that the validation routine can be run for several groups in the same pass.

As Hibernate Validator documentation says:

In order to implement such a validation order you just need to define an interface and annotate it with @GroupSequence, defining the order in which the groups have to be validated (see Defining a group sequence). If at least one constraint fails in a sequenced group, none of the constraints of the following groups in the sequence get validated.

First, you have to define constraint groups and apply them to the constraints:

public interface CheckItFirst {}

public interface ThenCheckIt {}

public class FormModel {

    @NotBlank
    private String name;

    @NotNull(groups = CheckItFirst.class)
    @ImageSizeConstraint(groups = ThenCheckIt.class)
    private MultipartFile image;
}

And then, as constraints are evaluated in no particular order, regardless of which groups they belong to (Default group too), you have to create @GroupSequence for your image field constraints groups.

@GroupSequence({ CheckItFirst.class, ThenCheckIt.class })
public interface OrderedChecks {}

You can test it with

Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<FormModel>> constraintViolations =
                            validator.validate(formModel, OrderedChecks.class);

To apply this validation in Spring MVC Controller methods, you may use the @Validated annotation, which can specify the validation groups for method-level validation:

@PostMapping(value = "/processFormModel")
public String processFormModel(@Validated(OrderedChecks.class) FormModel formModel) {
    <...>
}

Upvotes: 5

Related Questions