javax-bigdecimal-validation
Javax BigDecimal Validation
1. Introduction
In the tutorial Java Bean Validation Basics, we saw how to apply basic javax validation to various types, and in this tutorial, we’ll focus on using javax validation with BigDecimal.
2. Validating BigDecimal Instances
Luckily, we have a dedicated set of annotations for working with them:
-
@DecimalMin
-
@Digits
-
@DecimalMax
Let’s see our Invoice class, which has a field of type 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
2.2. @DecimalMax
@DecimalMax is the counterpart of @DecimalMin. The annotated element must be a number whose value is lower or equal to the specified maximum. @DecimalMax has an inclusive attribute that specifies whether the specified maximum value is inclusive or exclusive.
Also, @Min and @Max accept long values only. In @DecimalMin and @DecimalMax, we can specify the value in string format, which can be of any numeric type.
2.3. @Digits
In many cases, we need to validate the number of digits in the integral part and fraction part of a decimal number.
The @Digit annotation has two attributes, integer and fraction, for specifying the number of allowed digits in the integral part and fraction part of the number.
As per the official documentation, integer allows us to specify the maximum number of integral digits accepted for this number. But this is true only for non-decimal numbers. For decimal numbers, it checks the exact number of digits in an integral part of the number. We will see this in our test case.
Similarly, the fraction attribute allows us to specify the maximum number of fractional digits accepted for this number.
2.4. Test Cases
First, we’ll add a test that creates an Invoice with an invalid price according to our validation, and checks that the validation will fail:
public class InvoiceUnitTest {
private static Validator validator;
@BeforeClass
public static void setupValidatorInstance() {
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
@Test
public void whenPriceIntegerDigitLessThanThreeWithDecimalValue_thenShouldGiveConstraintViolations() {
Invoice invoice = new Invoice(new BigDecimal(10.21), "Book purchased");
Set<ConstraintViolation<Invoice>> violations = validator.validate(invoice);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> assertThat(action.getMessage())
.isEqualTo("numeric value out of bounds (<3 digits>.<2 digits> expected)"));
}
}
Now let’s check the validation with a correct price that’s an integer value:
@Test
public void whenPriceIntegerDigitLessThanThreeWithIntegerValue_thenShouldNotGiveConstraintViolations() {
Invoice invoice = new Invoice(new BigDecimal(10), "Book purchased");
Set<ConstraintViolation<Invoice>> violations = validator.validate(invoice);
assertThat(violations.size()).isEqualTo(0);
}
If we set a price with more than 3 digits in the integral part, we should see a validation error:
@Test
public void whenPriceIntegerDigitGreaterThanThree_thenShouldGiveConstraintViolations() {
Invoice invoice = new Invoice(new BigDecimal(1021.21), "Book purchased");
Set<ConstraintViolation<Invoice>> violations = validator.validate(invoice);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> assertThat(action.getMessage())
.isEqualTo("numeric value out of bounds (<3 digits>.<2 digits> expected)"));
}
A price equal to 000.00 should also a constraint validation:
@Test
public void whenPriceIsZero_thenShouldGiveConstraintViolations() {
Invoice invoice = new Invoice(new BigDecimal(000.00), "Book purchased");
Set<ConstraintViolation<Invoice>> violations = validator.validate(invoice);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> assertThat(action.getMessage())
.isEqualTo("must be greater than 0.0"));
}
Finally, let’s the case with a price that’s greater than 0:
@Test
public void whenPriceIsGreaterThanZero_thenShouldNotGiveConstraintViolations() {
Invoice invoice = new Invoice(new BigDecimal(100.50), "Book purchased");
Set<ConstraintViolation<Invoice>> violations = validator.validate(invoice);
assertThat(violations.size()).isEqualTo(0);
}
3. Conclusion
All code snippets can be found over on GitHub.