Why do bean validation Min/Max constraints not support the double type?
Asked Answered
C

2

31

Could somebody please explain to me why the JPA supports the double type as a field type, but the bean validation constaints in javax.validation.constraints (i.e. @Min/@Max) do not support it? I know documentation says this is due to rounding errors, but if I choose the field type to be double I already admit that I don't care that much about the explicit precision.

The scenario I ran into this dilemma is the following: I have an Entity that represents a point on the earth's surface. If the precision is within a few centimeters it's fine. It looks something like this:

@Entity
public class Point {

    /**
     * The longitude in radians.
     */
    @Min(-Math.Pi)
    @Max(Math.Pi)
    double longitude;
    /**
     * The latitude in radians.
     */
    @Min(-Math.Pi / 2)
    @Max(Math.Pi / 2)
    double latitude;

}

Unfortunately this does not work, because the annotations do not support the double type. But using BigDecimal instead is not really an option, because I have some extensive computation with multiple points going on that still needs to be reasonably fast. I worked around it by defining a custom constraint check that does work with doubles, but somehow I think there is something I'm missing in the whole story. So, what am I missing?

Canada answered 14/9, 2011 at 20:49 Comment(3)
Please note that JPA and Bean Validation are two entirely separate APIs. I fixed the title, some wording and tags accordingly. Brilliant question example btw. What Bean Validation implementation are you using? Hibernate Validator?Gower
Yes, right now I'm using Hibernate Validator.Canada
You actually can annotate a double with Min or Max (at least in Hibernate Validator). The double type is supported. Your problem seems to be that you cannot specify a double as constraint parameter. There the spec indeed enforces a long. Have you considered using DecimalMin and DecimalMax? You could specify your min and max values as strings.Swaim
D
9

It is because of rounding. But not because of the problem that a double is may not correct enough to express the number you want. It is more that the annotation value (of Min and Max) is of type long, so it can not express any number with decimal places. On the other hand you can not use a double to express exact all numbers that a long can express.

So the API designers had to decide for one of the two ways (long or double)

Denten answered 14/9, 2011 at 21:34 Comment(1)
Thanks for that insight, I didn't look at it from that point of view. But since long and double both use 64 bits, there is an isomorphism that preserves comparison. I guess this isomorphism isn't built in to Double or Float but it shouldn't be a more complex problem than converting a BigDecimal to a long. So, this explains why the support for doubles isn't built-in, but it shows that it is possible. And that should be enough to be supported, IMO.Canada
I
24

Use the @DecimalMin annotation. You will need to pass a literal String value, because the attrubute value must be constant (String.valueOf(- Math.PI)) doesn't work. It works to validate Double attributes.

@DecimalMin(value = "0.01", message = "Your message...")
private Double longitude;
Impregnable answered 4/12, 2019 at 16:10 Comment(4)
Works fine. Thanks!Jesher
The javadoc of the mentioned annotation explicitly says double is not supported: "Note that double and float are not supported due to rounding errors (some providers might provide some approximative support)." so i would spend patient using this.Biancabiancha
i guess this works (despite what the javadoc says) because the string value passed (in the annotation) is simply an argument to the BigDecimal constructor. see: github.com/hibernate/hibernate-validator/blob/…Variole
Yes @DecimalMin works nice, but i think the correct range could defined with: @DecimalMax(value = "180.0")@DecimalMin(value = "-180.0")Photothermic
D
9

It is because of rounding. But not because of the problem that a double is may not correct enough to express the number you want. It is more that the annotation value (of Min and Max) is of type long, so it can not express any number with decimal places. On the other hand you can not use a double to express exact all numbers that a long can express.

So the API designers had to decide for one of the two ways (long or double)

Denten answered 14/9, 2011 at 21:34 Comment(1)
Thanks for that insight, I didn't look at it from that point of view. But since long and double both use 64 bits, there is an isomorphism that preserves comparison. I guess this isomorphism isn't built in to Double or Float but it shouldn't be a more complex problem than converting a BigDecimal to a long. So, this explains why the support for doubles isn't built-in, but it shows that it is possible. And that should be enough to be supported, IMO.Canada

© 2022 - 2024 — McMap. All rights reserved.