【问题标题】:Validating double and float values using Hibernate Validator - bean validation使用 Hibernate Validator 验证 double 和 float 值 - bean 验证
【发布时间】:2013-03-18 23:40:36
【问题描述】:

我正在寻找一种方法来验证 Spring 命令 bean 中的 java.lang.Double 字段的最大值和最小值(一个值必须位于给定的值范围之间),例如,

public final class WeightBean
{
     @Max(groups={ValidationGroup.class}, value=Double.MAX_VALUE, message="some key or default message")
     @Min(groups={ValidationGroup.class}, value=1D, message="some key or default message")
     private Double txtWeight;  //Getter and setter.

     public interface ValidationGroup{}         
}

@Max@Min 都不能采用java.lang.Double 值。

请注意,由于舍入错误,不支持 double 和 float (一些提供商可能会提供一些近似支持)

那么验证这些字段的方法是什么?

我正在使用 Spring 3.2.0 和 Hibernate Validator 4.3.1 CR1。

【问题讨论】:

  • 如果你愿意,我可以在我的约束集合中实现一个 DoubleRangeValidator:waxolunist.github.com/validationconstraints - 只需打开一个问题,你明天就可以在 maven Central 上使用它。
  • @Waxolunist - 谢谢,但我没有得到。

标签: spring validation spring-mvc bean-validation hibernate-validator


【解决方案1】:

您可以使用注释,但根据情况可能会得到错误的结果。这是双打和 imo 在许多情况下的普遍问题,应该避免使用 _Double_s。也许切换到不同的类型是最好的解决方案? BigDecimal 例如?

【讨论】:

  • 我已切换到BigDecimal 类型,但@Max@Minvalue 属性只接受Long 值。我需要检查一个值是否在定义的范围之间。例如,从 0.1 到 0.9。这对 bean 验证来说是不可能的吗?
  • 对于BigDecimal,请参见@DecimalMin 注释。
【解决方案2】:

如果您已切换到 BigDecimal(或 BigInteger),则可以使用 @DecimalMin@DecimalMax。 但这仍然不是 float 或 double 的解决方案。

【讨论】:

    【解决方案3】:

    我避免了doublefloat 类型,并实现了一个自定义验证器,它可以根据精度和比例验证BigDecimal 值。

    约束描述符。

    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;
    }
    

    约束验证器。

    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;
        }
    }
    

    这也可以在需要时扩展到其他类型。


    最后在 bean 中,BigDecimal 类型的属性可以被 @BigDecimalRange 注解如下。

    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 {}
    }
    

    【讨论】:

      【解决方案4】:

      您也可以使用休眠验证器 API 中的@Digits

      @Digits(integer = 10 /*precision*/, fraction = 2 /*scale*/)
      

      【讨论】:

        【解决方案5】:

        有时与来自javax.validation.constraints@AssertTrue / @AssertFalse 配对很方便

        public final class WeightBean {
            @NotNull
            private Double txtWeight;  //Getter and setter.
        
            @AssertTrue
            public boolean getTxtWeightCheck() {
                return txtWeight > 0.1 && txtWeight < 0.9;
            }
        }
        

        【讨论】:

          【解决方案6】:

          较新版本的 Hibernate Validator(至少 6.0.17)支持 double 上的 @DecimalMin/Max 注释

          class for validation

          【讨论】:

            【解决方案7】:

            Hibernate 验证器将在 DoubleFloat 上为 @DecimalMin/Max 工作。但它们不是精确的数字,只是近似值,根据验证实现,可能会有一些错误的结果。

            验证的最佳想法是将BigDecimal 类型与@DecimalMin@DecimalMax 验证注释一起使用。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-02-08
              • 1970-01-01
              • 1970-01-01
              • 2013-06-04
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多