Search code examples
springspring-bootvalidationhibernate-validatorspring-validator

spring boot validation for Long values


This is class against which we are going to map the incoming request

@Getter
@Setter
public class FooRequest {
    @Size(max = 255, message = "{error.foo.name.size}")
    private String name;

    @Digits(integer = 15, fraction = 0, message = "{error.foo.fooId.size}")
    private Long fooId;

    @Digits(integer = 15, fraction = 0, message = "{error.foo.barId.size}")
    private Long barId;
    }

I have used javax.validation.constraints.* like above. If we send request like

{
    "name": "Test",
    "fooId": "0001234567",
    "barId": "0003456789"
    }

Then It works fine and we are able to save the results in the database but if we send it like:

{
    "name": "Test",
    "fooId": 0001234567,
    "barId": 0003456789
    }

Then we are getting 400 Bad Request. I am not getting it what wrong am I doing, I just want to ensure that user sends digits, having length between 1-15 and wants to map it against the Long variable. Is it because of fraction or because all these values are starting with 0?


Solution

  • The second JSON is not a valid json because of the leading zeroes.

    Background

    Spring uses Jackson library for JSON interactions.

    The Jackson's ObjectMapper by default throws if you try to parse the second JSON:

    public class Main {
        public static void main(String[] args) throws IOException {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.readValue("{\"name\": \"Test\", \"fooId\": 0001234567, \"barId\": 0003456789}", FooRequest.class);
        }
    }
    
    

    The exception is:

    Exception in thread "main" com.fasterxml.jackson.core.JsonParseException: Invalid numeric value: Leading zeroes not allowed
     at [Source: (String)"{"name": "Test", "fooId": 0001234567, "barId": 0003456789}"; line: 1, column: 28]
    

    One can allow leading zeroes via the JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS:

    public class Main {
        public static void main(String[] args) throws IOException {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
            FooRequest fooRequest = objectMapper.readValue("{\"name\": \"Test\", \"fooId\": 0001234567, \"barId\": 0003456789}", FooRequest.class);
    
            System.out.println(fooRequest.getBarId());
        }
    }
    

    Or in spring via the Spring Boot's application.properties:

    spring.jackson.parser.allow-numeric-leading-zeros=true
    

    then, the second JSON will be parsed successfully.

    Why does it work with the first JSON?

    Because by default Jackson's MapperFeature.ALLOW_COERCION_OF_SCALARS is turned on.

    From its javadoc:

    When feature is enabled, conversions from JSON String are allowed, as long as textual value matches (for example, String "true" is allowed as equivalent of JSON boolean token true; or String "1.0" for double).


    because all these values are starting with 0?

    So it turns out that, yes, but for a slightly different reason