11thdimension
11thdimension

Reputation: 10633

Spring Boot validation takes float value in integer field

I'm trying to implement a POST service with request validation.

My Controller method looks something like below

public void updateScore(@Valid ScoreRequest)

ScoreRequest looks like below

import javax.validation.constraints.*;
import lombok.Data;

@Data
public class ScoreRequest {
    @Min(0)
    @Max(100)
    @Digits(fraction = 0, integer = 3)
    private Integer score;

    ...
}

It all works fine till I pass integer values for score, however If I pass fraction part as well, request goes through and Spring somehow truncates the fraction and uses the integer part in the request.

I was expecting it to throw a validation error since datatype of score doesn't match.

It works with followling request, and uses 10 as the score value in the request object. I'm expecting it to throw an error, what am I doing wrong?

{"score": 10.234234}

Spring Boot version: 2.0.3.RELEASE

Upvotes: 1

Views: 8738

Answers (3)

11thdimension
11thdimension

Reputation: 10633

I was trying to debug Spring Boot's validation classes to find what was happening, but after looking at the comment by @M.Denium I searched for Jackson issues and found a related SO entry.

Java Jackson - prevent float to int conversion when deserializing

I'm using answer by @Jichao Zhang, however Just to confirm answer by @Eduardo Sanchez-Ros works as well. This is what works for me.

ObjectMapper.configure(DESERIALIZATION_FEATURE.ACCEPT_FLOAT_AS_INT, false);

Upvotes: 1

swayamraina
swayamraina

Reputation: 3158

If you closely look at the definition of the @digits annotation,

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })

So this annotation can be applied to methods also.
If you read the docs, it says this annotation can be applied to the following types

  • BigDecimal
  • BigInteger
  • CharSequence
  • byte (or Byte)
  • short (or Short)
  • int (or Integer)
  • long (or Long)

the integer field of the annotation checks for the number of integral digits while the fraction field of the annotation checks for the number of fractional digits.

Since, you declared your field to be an Integer value. It casts the value to an integer and truncates the fractional part.
This does not fail validations as both the fields satisfy the validation.

This annotation is ideally to be only used with BigDecimal type.

Upvotes: 0

amer
amer

Reputation: 1672

Don't use this annotation: @Digits(fraction = 0, integer = 3 with Integer since it is useless to set fractions for Integer.

Why don't you do:

@Min(0)
@Max(100)
@Digits(fraction = 0, integer = 3)
private BigDecimal score;

Upvotes: 0

Related Questions