Search code examples
javavalidationspring-bootbean-validationspring-web

"Invalid property 'ssn' of bean class [java.lang.String]" when trying to validate request body with Spring


I have a springboot application with a rest controller sitting up top. The user access the controller through /test and passes in a json like so:

{"ssn":"123456789"}

I want to validate the input by at least making sure there's not an empty ssn being passed in like so:

{"ssn":""}

So here's my controller:

@RequestMapping(
            value = "/test",
            method = RequestMethod.POST,
            consumes = "application/json",
            produces = "application/json")
@ResponseBody
public JsonNode getStuff(@RequestHeader HttpHeaders header,
                                 @RequestBody String payload,
                                 BindingResult bindingResult) {
    validator.validate(payload, bindingResult);
    if(bindingResult.hasErrors()) {
        throw new InvalidRequestException("The request is incorrect", bindingResult);
    }
    /* doing other stuff */
}

And here's my validator:

@Component
public class RequestValidator implements Validator {
    @Override
    public boolean supports(Class<?> clazz) {
        return false;
    }

    @Override
    public void validate(Object target, Errors errors) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode ssn = null;
        try {
            ssn = mapper.readTree((String) target);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if(ssn.path("ssn").isMissingNode() || ssn.path("ssn").asText().isEmpty()) {
            errors.rejectValue("ssn", "Missing ssn", new Object[]{"'ssn'"}, "Must provide a valid ssn.");
        }
    }
}

I tried testing this with postman and I keep getting this error:

HTTP Status 500 - Invalid property 'ssn' of bean class [java.lang.String]: Bean property 'ssn' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?

What exactly is the problem here? I don't understand what it's talking about in relation to getters and setters.

Edit 1: The value of the payload as requested

{"ssn":""}

Solution

  • By default Spring Boot configures Json parser, so any Json you pass to the controller will be parsed. Spring is expecting an object with a property called 'ssn' to bind the request value.

    This means that you should create a model object like this:

    public class Data {
        String ssn;
    
    }
    

    And use it to bind your request body like this:

    @RequestMapping(
            value = "/test",
            method = RequestMethod.POST,
            consumes = "application/json",
            produces = "application/json")
    @ResponseBody
    public JsonNode getStuff(@RequestHeader HttpHeaders header,
                                     @RequestBody Data payload,
                                     BindingResult bindingResult) {
        validator.validate(payload, bindingResult);
        if(bindingResult.hasErrors()) {
            throw new InvalidRequestException("The request is incorrect", bindingResult);
        }
        /* doing other stuff */
    }
    

    You also need to adapt your Validator to use this new Data object.