Spring Data Rest Validation Confusion

后端 未结 3 1055
情书的邮戳
情书的邮戳 2020-12-13 16:40

Looking for some help with Spring data rest validation regarding proper handling of validation errors:

I\'m so confused with the docs regarding spring-data-rest vali

相关标签:
3条回答
  • 2020-12-13 16:52

    The answers by @Mathias and @1977 is enough for regular Spring Data REST calls. However in cases when you need to write custom @RepositoryRestControllers using @RequestBody and @Valid JSR-303 annotations didn't work for me.

    So, as an addition to the answer, in case of custom @RepositoryRestControllers with @RequestBody and @Valid annotation I've added the following @ControllerAdvice:

    /**
     * Workaround class for making JSR-303 annotation validation work for controller method parameters.
     * Check the issue <a href="https://jira.spring.io/browse/DATAREST-593">DATAREST-593</a>
     */
    
        @ControllerAdvice
        public class RequestBodyValidationProcessor extends RequestBodyAdviceAdapter {
    
            private final Validator validator;
    
            public RequestBodyValidationProcessor(@Autowired @Qualifier("mvcValidator") final Validator validator) {
                this.validator = validator;
            }
    
            @Override
            public boolean supports(final MethodParameter methodParameter, final Type targetType, final Class<? extends
                    HttpMessageConverter<?>> converterType) {
                final Annotation[] parameterAnnotations = methodParameter.getParameterAnnotations();
                for (final Annotation annotation : parameterAnnotations) {
                    if (annotation.annotationType().equals(Valid.class)) {
                        return true;
                    }
                }
    
                return false;
            }
    
            @Override
            public Object afterBodyRead(final Object body, final HttpInputMessage inputMessage, final MethodParameter
                    parameter, final Type targetType, final Class<? extends HttpMessageConverter<?>> converterType) {
                final Object obj = super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
                final BindingResult bindingResult = new BeanPropertyBindingResult(obj, obj.getClass().getCanonicalName());
                validator.validate(obj, bindingResult);
                if (bindingResult.hasErrors()) {
                    throw new RuntimeBindException(bindingResult);
                }
    
                return obj;
            }
        }
    
    0 讨论(0)
  • 2020-12-13 17:10

    @Mathias it seems the following is enough for jsr 303 annotations to be checked and for it to auto return a http code of 400 with nice messages (I dont even need BeforeCreateCompanyValidator or BeforeSaveCompanyValidator classes):

    @Configuration
    public class RestValidationConfiguration extends RepositoryRestConfigurerAdapter{
    
    @Bean
    @Primary
    /**
     * Create a validator to use in bean validation - primary to be able to autowire without qualifier
     */
    Validator validator() {
        return new LocalValidatorFactoryBean();
    }
    
    
    @Override
    public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
        Validator validator = validator();
        //bean validation always before save and create
        validatingListener.addValidator("beforeCreate", validator);
        validatingListener.addValidator("beforeSave", validator);
    }
    

    }

    400 response:

    {
        "errors": [{
            "entity": "Company",
            "message": "may not be null",
            "invalidValue": "null",
            "property": "name"
        }, {
            "entity": "Company",
            "message": "may not be null",
            "invalidValue": "null",
            "property": "address"
        }]
    }
    
    0 讨论(0)
  • 2020-12-13 17:14

    I think your problem is that the bean validation is happening too late - it is done on the JPA level before persist. I found that - unlike spring mvc - spring-data-rest is not doing bean validation when a controller method is invoked. You will need some extra configuration for this.

    You want spring-data-rest to validate your bean - this will give you nice error messages responses and a proper http return code.

    I configured my validation in spring-data-rest like this:

    @Configuration
    public class MySpringDataRestValidationConfiguration extends RepositoryRestConfigurerAdapter {
    
        @Bean
        @Primary
        /**
         * Create a validator to use in bean validation - primary to be able to autowire without qualifier
         */
        Validator validator() {
            return new LocalValidatorFactoryBean();
        }
    
        @Bean
        //the bean name starting with beforeCreate will result into registering the validator before insert
        public BeforeCreateCompanyValidator beforeCreateCompanyValidator() {
            return new BeforeCreateCompanyValidator();
        }
    
        @Override
        public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
            Validator validator = validator();
            //bean validation always before save and create
            validatingListener.addValidator("beforeCreate", validator);
            validatingListener.addValidator("beforeSave", validator);
        }
    }
    

    When bean validation and/or my custom validator find errors I receive a 400 - bad request with a payload like this:

        Status = 400
        Error message = null
        Headers = {Content-Type=[application/hal+json]}
        Content type = application/hal+json
       Body = {
         "errors" : [ {
         "entity" : "siteWithAdminUser",
         "message" : "may not be null",
         "invalidValue" : "null",
         "property" : "adminUser"
         } ]
       }
    
    0 讨论(0)
提交回复
热议问题