The Spring validation @NotNull does not validate

14,714

Solution 1

I think I found the answer thanks to this post:

jsr-303-valid-annotation-nested-object-not-working

So as soon as I added the @Valid to these fields:

@Valid
private List<Mapping> mappings;

And these fields inside Mapping:

@JsonProperty(value="account_id")
    @Valid
    @NotNull
    private String accountId;

    @JsonProperty(value="last_updated_at")
    @Valid
    @NotNull    
    private OffsetDateTime lastUpdatedAt;

The validation started working.

Also I removed the @NotNull in the setter() methods:

Setters() like this:

@Override
    public void setAccountId (String accountId) {
        this.accountId = accountId;
    }    

    @Override
    public void setLastUpdatedAt(OffsetDateTime lastUpdatedAt) {
        this.lastUpdatedAt = lastUpdatedAt;
    }

Also my code worked without any of the Validator beans which I added to Main().

Solution 2

In my case, I was missing the validation dependency. From baeldung;

Starting with Boot 2.3, we also need to explicitly add the spring-boot-starter-validation dependency:

<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-validation</artifactId> 
</dependency>
Share:
14,714
blueSky
Author by

blueSky

Updated on June 14, 2022

Comments

  • blueSky
    blueSky almost 2 years

    I’m trying to validate a POST request using Spring Validator. This is the Object I’m trying to validate:

    @Validated
    public class Request implements Serializable {
        private static final long serialVersionUID = 1L;
    
        private Long id1;
        private Long id2;   
        private String s;   
        private List<Mapping> mappings;
    
        public Request() {}
        public Request (Long id1, Long id2, String s, List<Mapping> mappings) {
            this.id1 = id1;
            this.id2 = id2;
            this.s = s;
            this.mappings = mappings;
        }
    
        //getter() and setter() methods.
    }
    

    And this is the Mapping class:

    @Validated
    public class Mapping implements Serializable {
        private static final long serialVersionUID = 1L;
        @JsonProperty(value="id")
        private Long id;
    
        @JsonProperty(value="string")
        private String string;
    
        @JsonProperty(value="account_id")
        @NotNull
        private String accountId;
    
        @JsonProperty(value="last_updated_at")
        @NotNull    
        private OffsetDateTime lastUpdatedAt;
    
        // Getter and setters()
        // I'll skip the getter() and setter() for id and string fields.
        @Override
        public String getAccountId() {
            return accountId;
        }
    
        @Override
        public void setAccountId (@NotNull String accountId) {
            this.accountId = accountId;
        }
    
        @Override
        public OffsetDateTime getLastUpdatedAt() {
            return lastUpdatedAt;
        }
    
        @Override
        public void setLastUpdatedAt(@NotNull OffsetDateTime lastUpdatedAt) {
            this.lastUpdatedAt = lastUpdatedAt;
        }
    }
    

    This is the message being posted:

    [Request [id1=null, id2=null, s=6eq2J6, mappings=
    
    [Mapping [id=2779, string=6eq2J6, accountId=null, lastUpdatedAt=null]]]]
    

    This is how I receive the request, but the bindingResult.hasErrors() is always empty. The pushRequest is exactly as it was sent.

    @RestController
    @RequestMapping(value="/${path}", method={RequestMethod.GET, RequestMethod.POST, RequestMethod.PUT})
    @Validated
    public class MappingController {
    
    @PostMapping(value="/", consumes={"application/json"})
    public void processMappings (@Valid @RequestBody Optional<Request> pushRequest, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            log.info("Error!");
        }
    }
    }
    

    Why the @NotNull for accountId and lastUpdatedAt does not make the validation to fail when they have Null value?

    I've tried to find the solution by searching this error, the solutions was to add @Validated to the Request, Mapping and MappingController classes, which did not solve the problem.

    Another solution was to add these Beans to the Main() class, which did not solve the problem.

    public class Main {
        public static void main(String[] args) {        
            SpringApplication.run(Main.class, args);        
            //System.out.println("version: " + SpringVersion.getVersion()); // version: 5.1.0.RC1
        }
    
        @Bean
        public javax.validation.Validator localValidatorFactoryBean() {
           return new LocalValidatorFactoryBean();
        }
    
        @Bean
        public MethodValidationPostProcessor methodValidationPostProcessor() {
                    MethodValidationPostProcessor mvProcessor = new MethodValidationPostProcessor();
                    mvProcessor.setValidator(validator());
                    return mvProcessor;
        }
    
        @Bean
        public LocalValidatorFactoryBean validator() {
                        LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
                        validator.setProviderClass(HibernateValidator.class);
                        validator.afterPropertiesSet();
                        return validator;
        }
    }