Search code examples
javavalidationlambdabean-validationmicronaut

Validating a lambda request in Micronaut using ConstraintValidator


I have a handler like this and a custom annotation @ValidRequest:

@Introspected
public class MessageHandler extends MicronautRequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {

  @Override
  public APIGatewayProxyResponseEvent execute(@ValidRequest APIGatewayProxyRequestEvent event) {
    return new APIGatewayProxyResponseEvent()
        .withStatusCode(200)
        .withHeaders(Collections.singletonMap("Content-Type", "application/json"))
        .withBody("OK");
  }

}

The annotation itself looks like this:

@Retention(RUNTIME)
@Constraint(validatedBy = {ValidRequestValidator.class})
public @interface ValidRequest {

  String message() default "Request is not valid";
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() default {};

}

And the validator is like this:

@Introspected
public class ValidRequestValidator implements ConstraintValidator<ValidRequest, APIGatewayProxyRequestEvent> {

  @Override
  public boolean isValid(
      @Nullable APIGatewayProxyRequestEvent event,
      @NonNull AnnotationValue<ValidRequest> annotationMetadata,
      @NonNull ConstraintValidatorContext context
  ) {
    if (event == null || event.getBody() == null || event.getBody().isEmpty()) {
      throw new RuntimeException("Incorrect request event");
    }
    return true;
  }

}

The problem is that validation is completely ignored. I can send any events with or without body and everything works without exception. I did everything according to the Micronout documentation, what could be wrong?

https://docs.micronaut.io/latest/guide/index.html#beanValidation


Solution

  • Please remove the @Introspect from your validator and try to follow the same as I have done below.

    @POST
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces(MediaType.APPLICATION_JSON)
    @Path("/somePath")
    public Response workingWithSubscription( @Valid UpdateSubscription updateSubscription) {
    

    @ValidUpdateSubscription
    public class UpdateSubscription implements UpdateSubscriptionRequest {
    
    }
    

    @Target({TYPE})
    @Retention(RUNTIME)
    @Constraint(validatedBy = UpdateSubscriptionValidator.class)
    @Documented
    public @interface ValidUpdateSubscription {
    
        int ERROR_CODE = 1111;
    
        String message() default "Null value";
    
        Class<?>[] groups() default {};
    
        Class<? extends Payload>[] payload() default {};
    
        int errorCode() default ERROR_CODE;
    
        Response.Status status() default Response.Status.BAD_REQUEST;
    }
    

    @Named
    @ApplicationScoped
    public class UpdateSubscriptionValidator implements ConstraintValidator<ValidUpdateSubscription, UpdateSubscription> {
    
        @Override
        public boolean isValid(UpdateSubscription value, ConstraintValidatorContext context) {
    
            return true/OR/false;
        }
    }