Environment

Spring Boot: 3.3.6 Spring Web: 6.1.15 Java: 21

Context:

A @RequestMapping that makes use of @Constraint annotations to validate @RequestHeader and uses @Valid annotation to validate @RequestBody.

Controller

@RestController
@RequestMapping("/api")
public class DemoController {

    @PostMapping("/test")
    public Mono<String> test(
            @RequestHeader(name = "x-channel") @Size(min=4, max=4) String channel,
            @Valid @RequestBody RequestDto requestDto
    ) {
        return Mono.just("test");
    }
}

Dto

@ValidatorTestAnnotation
public record RequestDto(@NotEmpty String id) {
}

Please note that the RequestDto uses @Constraint annotations at field level and also class level.

CustomAnnotation and Validator

@Constraint(validatedBy = TestAnnotationValidator.class)
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidatorTestAnnotation {
    String message() default "Example fail message";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

public class TestAnnotationValidator implements ConstraintValidator<ValidatorTestAnnotation, RequestDto> {

    @Override
    public boolean isValid(RequestDto dto, ConstraintValidatorContext context) {
        // Dummy validation. Return false for the purpose of this example
        return false;
    }
}

Since I have @Contraint annotations declared directly on method parameters, the exception raised is HandlerMethodValidationException.

I'm using the HandlerMethodValidationException.visitResults to handle the errors.

@RestControllerAdvice
public class DemoControllerAdvice {

    @ExceptionHandler(HandlerMethodValidationException.class)
    public String handlerMethodValidationException(HandlerMethodValidationException e) {
        e.visitResults(new HandlerMethodValidationException.Visitor() {
            @Override
            //implementation...

Issue:

When I use a @Constraint annotation at class level, the HandlerMethodValidationException validationResult list is composed of a ParameterValidationResult instead of a ParameterErrors object.

debug

This fails in the visitor assertion that exists in HandlerMethodValidationException.asErrors method:

(...)
RequestBody requestBody = param.getParameterAnnotation(RequestBody.class);
    if (requestBody != null) {
        visitor.requestBody(requestBody, asErrors(result));
        continue;
    }

(...)
private static ParameterErrors asErrors(ParameterValidationResult result) {
    Assert.state(result instanceof ParameterErrors, "Expected ParameterErrors");    <------- FAILS HERE
    return (ParameterErrors) result;
}

Thanks for the support.