Validating double and float values using Hibernate Validator - bean validation

前端 未结 6 1430
心在旅途
心在旅途 2020-12-29 11:16

I\'m looking for a way to validate a java.lang.Double field in the Spring command bean for its maximum and minimum values (a value must lie between a given rang

相关标签:
6条回答
  • 2020-12-29 11:23

    Newer versions of Hibernate Validator (at least 6.0.17) supports @DecimalMin/Max annotation on double

    See class for validation

    0 讨论(0)
  • 2020-12-29 11:28

    You can also use @Digits from the hibernate validator API as well

    @Digits(integer = 10 /*precision*/, fraction = 2 /*scale*/)
    
    0 讨论(0)
  • 2020-12-29 11:29

    If you have switched to BigDecimal (or BigInteger), you could use @DecimalMin or @DecimalMax. But this is still no solution for float or double.

    0 讨论(0)
  • 2020-12-29 11:30

    Sometimes it's convenient in pair with @AssertTrue / @AssertFalse from javax.validation.constraints

    public final class WeightBean {
        @NotNull
        private Double txtWeight;  //Getter and setter.
    
        @AssertTrue
        public boolean getTxtWeightCheck() {
            return txtWeight > 0.1 && txtWeight < 0.9;
        }
    }
    
    0 讨论(0)
  • 2020-12-29 11:36

    You can use the annotation, but you might get false results depending. This is a general problem with doubles and imo in many cases _Double_s should be avoided. Maybe switching to a different type is the best solution? BigDecimal for example?

    0 讨论(0)
  • I have avoided the double and the float types and implemented a custom validator that could validate a BigDecimal value based on the precision and the scale.

    The constraint descriptor.

    package constraintdescriptor;
    
    import constraintvalidator.BigDecimalRangeValidator;
    import java.lang.annotation.Documented;
    import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
    import static java.lang.annotation.ElementType.FIELD;
    import static java.lang.annotation.ElementType.METHOD;
    import java.lang.annotation.Retention;
    import static java.lang.annotation.RetentionPolicy.RUNTIME;
    import java.lang.annotation.Target;
    import javax.validation.Constraint;
    import javax.validation.Payload;
    
    @Target({METHOD, FIELD, ANNOTATION_TYPE})
    @Retention(RUNTIME)
    @Constraint(validatedBy = BigDecimalRangeValidator.class)
    @Documented
    public @interface BigDecimalRange {
        public String message() default "{java.math.BigDecimal.range.error}";
        public Class<?>[] groups() default {};
        public Class<? extends Payload>[] payload() default {};
    
        long minPrecision() default Long.MIN_VALUE;
        long maxPrecision() default Long.MAX_VALUE;
        int scale() default 0;
    }
    

    The constraint validator.

    package constraintvalidator;
    
    import constraintdescriptor.BigDecimalRange;
    import java.math.BigDecimal;
    import javax.validation.ConstraintValidator;
    import javax.validation.ConstraintValidatorContext;
    
    public final class BigDecimalRangeValidator implements ConstraintValidator<BigDecimalRange, Object> {
    
        private long maxPrecision;
        private long minPrecision;
        private int scale;
    
        @Override
        public void initialize(final BigDecimalRange bigDecimalRange) {
            maxPrecision = bigDecimalRange.maxPrecision();
            minPrecision = bigDecimalRange.minPrecision();
            scale = bigDecimalRange.scale();
        }
    
        @Override
        public boolean isValid(final Object object, final ConstraintValidatorContext cvc) {
            boolean isValid = false;
    
            if (object == null) { // This should be validated by the not null validator (@NotNull).
                isValid = true;
            } else if (object instanceof BigDecimal) {
                BigDecimal bigDecimal = new BigDecimal(object.toString());
                int actualPrecision = bigDecimal.precision();
                int actualScale = bigDecimal.scale();
                isValid = actualPrecision >= minPrecision && actualPrecision <= maxPrecision && actualScale <= scale;
    
                if (!isValid) {
                    cvc.disableDefaultConstraintViolation();
                    cvc.buildConstraintViolationWithTemplate("Precision expected (minimun : " + minPrecision + ", maximum : " + maxPrecision + "). Maximum scale expected : " + scale + ". Found precision : " + actualPrecision + ", scale : " + actualScale).addConstraintViolation();
                }
            }
    
            return isValid;
        }
    }
    

    This could be extended for other types as well, as and when required.


    And finally in the bean, the property of the type BigDecimal could be annotated by the @BigDecimalRange annotation as follows.

    package validatorbeans;
    
    public final class WeightBean {
    
        @BigDecimalRange(minPrecision = 1, maxPrecision = 33, scale = 2, groups = {ValidationGroup.class}, message = "The precision and the scale should be less than or equal to 35 and 2 respectively.")
        private BigDecimal txtWeight; // Getter and setter.
    
        public interface ValidationGroup {}
    }
    
    0 讨论(0)
提交回复
热议问题