micronaut-core
micronaut-core copied to clipboard
@Digits validation fails to raise constraint error for illegal BigDecimal arguments
Expected Behavior
Given the following classes, each with a BigDecimal
property. One has validation constraint on the constructor arg, the other on the field.
@Introspected
class Offer {
@Digits(integer = 6, fraction = 2)
BigDecimal price
}
@Introspected
class CounterOffer {
BigDecimal price
CounterOffer(@Digits(integer = 6, fraction = 2) BigDecimal price) {
this.price = price
}
}
The following test asserts the validation constraint checks fail, as expected. The test should pass:
void "test BigDecimal Digits property validation"() {
when:
Offer offer = new Offer(price: 1234567.890)
def violations = validator.validate(offer)
then:
violations.size() > 0
when:
CounterOffer counterOffer = new CounterOffer(9876543.210)
violations = validator.validate(counterOffer)
then:
violations.size() == 1
}
Actual Behaviour
The first validation check (for Offer
) passes, where the constraint is annotated on the class field.
The second (for CounterOffer
) – where the constructor argument rather than class field is annotated with the constraint - fails to raise the same violation as it should, so the illegal constructor argument sneaks past the Validator
.
Condition not satisfied:
violations.size() == 1
| | |
[] 0 false
This is apparently an issue not just with constructor arguments, but method arguments in general. The following also fails to raise validation errors for illegal BigDecimal arguments.
@SingleResult
Publisher<Offer> save(
@NotBlank String slug,
@Digits(integer = 6, fraction = 2) BigDecimal price,
@NotNull Duration duration,
@NotBlank String description);
I have only tested this with BigDecimal, so it might also be a problem with other @Digits
compatible types (BigInteger
, CharSequence
, etc).
Steps To Reproduce
No response
Environment Information
No response
Example Application
No response
Version
3.5.0 (also occurs with 3.4.x)
I think this is normal? .validate
checks the constraints of the property, but it can't know that the constructor was called incorrectly. Similar for method calls.
You get the same behavior for other validation annotations, like @NotBlank
with a String value:
@Inject
Validator validator;
void "test BigDecimal Digits property validation"() {
when:
Offer offer = new Offer(price: " ")
def violations = validator.validate(offer)
then:
violations.size() > 0
when:
CounterOffer counterOffer = new CounterOffer(" ")
violations = validator.validate(counterOffer)
then:
violations.size() == 1
}
@Introspected
static class Offer {
@NotBlank
String price
}
@Introspected
static class CounterOffer {
String price
CounterOffer(@NotBlank String price) {
this.price = price
}
}