0

We use Spring Kafka together with Spring Boot (all latest versions). We switched handling of Kafka messages into @KafkaHandler annotated methods and expected that @Valid/@Validated together with @Payload will ensure payload validation, but that did not happen. This feature is working for @KafkaListener, should it be also working for @KafkaHandler?

@KafkaListener(...)
@Component
public class NotificationListener {

    @KafkaHandler
    public void handleV1(@Payload @Valid NotificationV1 notification) {

Thank you.

ITman
  • 141
  • 2
  • 12

2 Answers2

2

The reason that why @KafkaListener works with @Valid annotation is that it just like a restful controller endpoint, which is the entrance of the service. The team works to add support for validation working on these situations, and it can be found that this validation mechanism is added in 2018.

As for @KafkaHandler, I'm not that familiar with spring-kafka, but if the validation just not work, it just means that the team doesn't add support for this situation. I recommend you to use the Spring Boot Method Validation Feature, which works fine for all spring managed beans and all the standard validation annotations such as @Size. One last thing, be careful about the exception thrown while validation fails.

Lebecca
  • 2,406
  • 15
  • 32
  • For more information about validation in Spring Boot, I have written an [answer](https://stackoverflow.com/a/54394177/9304616) that gives many reference articles. – Lebecca Jan 09 '21 at 17:39
  • I think that service validation and controller endpoint validations are different topics. I guess that Spring Kafka depends on Spring Messaging and there is different path to ensure validation. I was able to track it into [PayloadMethodArgumentResolver](https://github.com/spring-projects/spring-framework/blob/master/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PayloadMethodArgumentResolver.java#L202). I checked that this resolver is properly auto configured and for `@KafkaListener` resolver is correctly applied, but not for `@KafkaHandler`. – ITman Jan 10 '21 at 14:51
  • 1
    To make it clear, there are two pairs. Controller/Service, KafkaListener/KafkaHandler, both Controller and KafkaListener works with @Valid automatically because they are enhanced to work as so. You dig into `PayloadMethodArgumentResolver` for KafkaListener, I also dig into `RequestResponseBodyMethodProcessor` for the mechanism of Controller validation. As for Service/KafakaHandler, they are the same kind of things in my opinion, and Spring leaves their validation to work not that silently, so I suggest you use `Spring Boot Method Validation Feature` to take care of them. – Lebecca Jan 10 '21 at 16:28
  • I made some search, and the comparison I offered is not that accurate. I will do more work on the topic. – Lebecca Jan 10 '21 at 16:55
2

The Validator is not applied in this case because we just don't reach the PayloadMethodArgumentResolver for that purpose.

The target payload for the multi-method @KafkaListener is resolved before we call the method because we definitely need to know which method to call. Such a logic is done in the InvocableHandlerMethod.getMethodArgumentValues():

        args[i] = findProvidedArgument(parameter, providedArgs);
        if (args[i] != null) {
            continue;
        }
        ...
        try {
            args[i] = this.resolvers.resolveArgument(parameter, message);
        }

The Validator functionality is done in those resolvers. The findProvidedArgument() gives us the payload converted before for execution and here we just don't check any annotations on parameters.

We probably need to poll validation logic into the DelegatingInvocableHandler when we have selected a handler and before its invocation...

Feel free to raise a GitHub issue so we don't forget that this is needed to be addressed somehow.

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • 1
    Thank you @Artem, issue has been raised: https://github.com/spring-projects/spring-kafka/issues/1675 – ITman Jan 11 '21 at 18:07