'How to cascade validation in a custom validator?

In a Spring project (4.3.14.RELEASE) I need to validate Map<String, List<InnerObj>> map in the MVC layer.

For this purpose I wrote a custom validator

public class MapValidator implements ConstraintValidator<ValidMap, Map<String, List<InnerObj>>> {

@Override
public boolean isValid(final Map<String, List<InnerObj>> map,
                       final ConstraintValidatorContext context) {
    if (map == null || map.size() == 0) {
        return false;
    }

    // iterations over all objects and validation

    return true;
}

and annotation

@Target({METHOD, FIELD, ANNOTATION_TYPE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = MapValidator.class)
public @interface ValidMap {
    String message() default "valid.map";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

How to force the validation to propagate (something like @Valid) to the inner object (List and InnerObj) from my validator?



Solution 1:[1]

In principle, you can inject the Spring-configured Validator into your MapValidator and call its validate method on list elements. You'll need, however, to integrate the resulting Set<ConstraintViolation<ISoftBetFRBCoinDTO>> into the ConstraintValidatorContext argument somehow.

This approach seems to be an overkill.

Actually, Bean Validation does support validating collection elements via @Valid for method arguments:

public void method(Map<String, List<@Valid Address>> addressMap) {

This usage of @Valid is called method validation in the Bean Validation specification.

It's just in order to activate method validation in Spring, you have to annotate the containing class with Spring's @Validated annotation:

@RestController
@Validated
public class HelloWorldController {
    
    @PostMapping("/hello")
    public Map<String, List<Address>> helloWorld(@RequestBody Map<String, List<@Valid Address>> addressMap) {
        return addressMap;
    }
}

From Spring documentation:

To be eligible for Spring-driven method validation, all target classes need to be annotated with Spring’s @Validated annotation, which can optionally also declare the validation groups to use. See MethodValidationPostProcessor for setup details with the Hibernate Validator and Bean Validation 1.1 providers.

See also the linked javadoc of MethodValidationPostProcessor.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Alexey Veleshko