Javax BigDecimal验证

2023/05/12

1. 简介

在教程Java Bean Validation基础中,我们看到了如何将基本的javax验证应用于各种类型,在本教程中,我们将重点介绍如何将javax验证与BigDecimal结合使用。

2. 验证BigDecimal实例

不幸的是,对于BigDecimal,我们不能使用经典的@Min或@Max javax注解,因为它们只接受long值

幸运的是,我们有一组专门的注解来处理它们:

  • @DecimalMin
  • @Digits
  • @DecimalMax

BigDecimal精度高,是金融计算的首选。

让我们看看我们的Invoice类,它有一个BigDecimal类型的字段:

public class Invoice {

    @DecimalMin(value = "0.0", inclusive = false)
    @Digits(integer=3, fraction=2)
    private BigDecimal price;
    private String description;

    public Invoice(BigDecimal price, String description) {
        this.price = price;
        this.description = description;
    }
}

2.1 @DecimalMin

带注解的元素必须是一个数字,其值大于或等于指定的最小值。@DecimalMin有一个inclusive属性,表示指定的最小值是包含还是不包含。

2.2 @DecimalMax

@DecimalMax是@DecimalMin的对应物。带注解的元素必须是一个数字,其值小于或等于指定的最大值。@DecimalMax有一个inclusive属性,表示指定的最大值是包含还是不包含。

另外,@Min和@Max只接受long值。在@DecimalMin和@DecimalMax中,我们可以指定字符串格式的值,可以是任何数字类型。

2.3 @Digit

在很多情况下,我们需要验证十进制数的整数部分和小数部分的位数。

@Digit注解有两个属性,integer和fraction,用于指定数字的整数部分和小数部分允许的位数

根据官方文档,integral允许我们指定该数字可接受的最大整数位数

类似地,fraction属性允许我们指定该数字可接受的最大小数位数

2.4 测试用例

让我们看看这些注解的实际效果。

首先,我们将添加一个测试,根据我们的验证创建一个具有无效price的Invoice,并检查验证是否会失败:

public class InvoiceUnitTest {

    private static Validator validator;

    @BeforeClass
    public static void setupValidatorInstance() {
        validator = Validation.buildDefaultValidatorFactory().getValidator();
    }

    @Test
    public void whenMoreThanThreeIntegerDigits_thenShouldGiveConstraintViolations() {
        Invoice invoice = new Invoice(new BigDecimal("1021.21"), "Book purchased");
        Set<ConstraintViolation<Invoice>> violations = validator.validate(invoice);
        assertThat(violations).hasSize(1);
        assertThat(violations)
                .extracting("message")
                .containsOnly("numeric value out of bounds (<3 digits>.<2 digits> expected)");
    }
}

现在让我们用正确的price检查验证:

@Test
public void whenLessThanThreeIntegerDigits_thenShouldNotGiveConstraintViolations() {
    Invoice invoice = new Invoice(new BigDecimal("10.21"), "Book purchased");
    Set<ConstraintViolation<Invoice>> violations = validator.validate(invoice);
    assertThat(violations).isEmpty();
}

以类似的方式,让我们看看小数部分的验证是如何工作的:

@Test
public void whenTwoFractionDigits_thenShouldNotGiveConstraintViolations() {
    Invoice invoice = new Invoice(new BigDecimal("99.99"), "Book purchased");
    Set<ConstraintViolation<Invoice>> violations = validator.validate(invoice);
    assertThat(violations).isEmpty();
}

@Test
public void whenMoreThanTwoFractionDigits_thenShouldGiveConstraintViolations() {
    Invoice invoice = new Invoice(new BigDecimal("99.999"), "Book purchased");
    Set<ConstraintViolation<Invoice>> violations = validator.validate(invoice);
    assertThat(violations).hasSize(1);
    assertThat(violations)
        .extracting("message")
        .containsOnly("numeric value out of bounds (<3 digits>.<2 digits> expected)");
}

等于0.00的price应该违反我们的约束:

@Test
public void whenPriceIsZero_thenShouldGiveConstraintViolations() {
    Invoice invoice = new Invoice(new BigDecimal("0.00"), "Book purchased");
    Set<ConstraintViolation<Invoice>> violations = validator.validate(invoice);
    assertThat(violations).hasSize(1);
    assertThat(violations)
        .extracting("message")
        .containsOnly("must be greater than 0.0");
}

最后,让我们看看price大于零的情况:

@Test
public void whenPriceIsGreaterThanZero_thenShouldNotGiveConstraintViolations() {
    Invoice invoice = new Invoice(new BigDecimal("100.50"), "Book purchased");
    Set<ConstraintViolation<Invoice>> violations = validator.validate(invoice);
    assertThat(violations).isEmpty();
}

3. 总结

在本文中,我们了解了如何对BigDecimal使用javax验证。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章