How to set validation groups dynamically

Viewed 276

I have a Spring Boot application where I want to validate a request body object with the @valid annotation.

@PostMapping("update")
public void upateSnippet(@Valid @RequestBody MyDto dto)

This works as expected. But I need to do the validation based on session specific informations. So I created validation groups which should be set dynamically. I don´t want to call the validator manually in the controller. The validation logic should be completely outside of the controller.

So what I´m trying to do is to register a custom MethodValidationInterceptor where I can specify the groups in determineValidationGroups().

public class SessionAwareValidationInterceptor extends MethodValidationInterceptor
{
    @Autowired
    public SessionAwareValidationInterceptor(Validator validator)
    {
        super(validator);
    }

    @Override
    protected Class<?>[] determineValidationGroups(MethodInvocation invocation)
    {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpSession session = requestAttributes.getRequest().getSession();
        //return groups from session
    }
}

In my configuration I register the interceptor as any other bean:

@Bean
public MethodValidationInterceptor methodValidationInterceptor(Validator validator)
{
    return new SessionAwareValidationInterceptor(validator);
}

But I have serveral problems with this:

  1. The @Valid annotation works on its own, but the MethodValidationInterceptor is only called when I add a @Validated annotation on the controller class.
  2. But even when I use both annotations combined, Spring does not use my custom interceptor.

How do I register my custom MethodValidationInterceptor? Or is there maybe an other way to register the validation groups dynamically? Plan B would be some custom constraint validators which get the necessary informations out of the session, but I would prefer the group approach.

1 Answers

I figured it out how to do it. I had to create a custom MethodValidationPostProcessor that returns my SessionAwareValidationInterceptor.

public class CustomMethodValidationPostProcessor extends MethodValidationPostProcessor {
    @Override
    @NotNull
    protected Advice createMethodValidationAdvice(Validator validator) {
        return validator != null ? new SessionAwareValidationInterceptor(validator) : new SessionAwareValidationInterceptor();
    }
}

Then I simply registered it as bean. This way, I was able to use my solution from above. To make it work, I have to use the @Validated annotation on class level and the @Valid annotation on the method parameter.

Related