Spring 3.2 validation on generic types

2019-07-30 06:08发布

I have an interface which looks like this:

@Validated
public interface Service<T extends Foo, N extends Bar> {
    @Valid
    @NotNull
    T doStuff(@Valid N bar);
}

And another one extending it:

public interface PhoneService extends Service<PhoneFoo, PhoneBar> {
}

My objects Foo and PhoneFoo look like this (and Bar and PhoneBar are similar) :

public abstract class Foo {

    @NotBlank(message = "Missing id")
    @Size(max = 50, message = "Invalid id")
    private String id;
}

public class PhoneFoo extends Foo {
    @NotBlank(message = "Missing number")
    @Size(max = 50, message = "Invalid number")
    private String number;
}

Finally, I basically have a controller implementing PhoneService, such as:

@Controller
public final class PhoneServiceController implements PhoneService {
    @RequestMapping(...)
    @Override
    @ResponseBody
    PhoneFoo doStuff(@RequestBody final PhoneBar bar) {
        // Do things...
    }
}

Now, the validation on the controller just doesn't work at all. I can put an empty id, or an empty number, and no exception will be raised. Is there something special to do for Spring to validate generic types? Any workaround? Is this resolved with Spring boot?

Edit: I do have the following beans defined as well, so that Spring can pick up on validation:

@Bean
public static MethodValidationPostProcessor methodValidationPostProcessor() {
    MethodValidationPostProcessor postProcessor = new MethodValidationPostProcessor();
    postProcessor.setProxyTargetClass(true);
    postProcessor.setValidator(validator());
    return postProcessor;
}

@Bean
public static Validator validator() {
    HibernateValidatorConfiguration configuration = (HibernateValidatorConfiguration) Validation
            .byDefaultProvider().configure();
    return configuration
            .messageInterpolator(
                    new ValueFormatterMessageInterpolator(configuration
                            .getDefaultMessageInterpolator())).buildValidatorFactory()
            .getValidator();
}

Note: Validation in my project used to work fine, before I introduced a generic interface. It seems to me that Spring doesn't know how to handle @Valid N bar. Or am I wrong?

1条回答
放荡不羁爱自由
2楼-- · 2019-07-30 06:21

To add validation to your service methods, you'll need to add an instance of MethodValidationPostProcessor.

@Bean
@ConditionalOnMissingBean(type = "javax.validation.Validator")
public LocalValidatorFactoryBean localValidatorFactoryBean() {
    return new LocalValidatorFactoryBean();
}

@Bean
@Autowired
@ConditionalOnMissingBean(type = "org.springframework.validation.beanvalidation.MethodValidationPostProcessor")
public MethodValidationPostProcessor methodValidationPostProcessor(Validator validator) {
    MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
    methodValidationPostProcessor.setValidator(validator);
    return methodValidationPostProcessor;
}

@see http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.html

查看更多
登录 后发表回答