JSR 303自定义聚合注解未正常生效:仅触发单个约束
问题
我创建了聚合多个校验约束的自定义注解@Name,集成了@NotNull、@Min(3)和@Size(min = 3, max = 30)。编写测试用例传入值"12"时,预期触发@Min和@Size两个约束违规,但实际仅@Size约束被触发,测试失败。
注解代码
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) @Documented @NotNull @Min(3) @Size(min = 3, max = 30) @Constraint(validatedBy = {}) public @interface Name { String message() default "lms.common.validation.Name.message"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
测试代码
@Slf4j @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) @ContextConfiguration(classes = { ValidationAutoConfiguration.class }) @SpringBootConfiguration class NameTest { private static class TestDto { @Name private final String name; public TestDto(String name) { this.name = name; } } @Autowired private Validator validator; @Test void validateWhenNameIsNotNullAndNotEmptyAndNotValid() { Set<ConstraintViolation<TestDto>> violations = validator.validate(new TestDto("12")); for (ConstraintViolation<TestDto> constraintViolation : violations) { log.warn("Constraint violation found, property = {}, message = {}", constraintViolation.getPropertyPath(), constraintViolation.getMessage()); } Assertions.assertThat(violations) .anyMatch(c -> testConstraint(c, "name", "size must be between 3 and 30")) .anyMatch(c -> testConstraint(c, "name", "must be greater than or equal to 3")); } private boolean testConstraint(ConstraintViolation<?> c, String expectedName, String messageStartWith) { return c.getPropertyPath().toString().equals(expectedName) && c.getMessage().startsWith(messageStartWith); } }
测试输出
Constraint violation found, property = name, message = size must be between 3 and 30
原因
@Min注解仅对数值类型(如int、long、BigDecimal等)生效,你的字段是String类型,校验框架在处理@Min时会直接忽略该约束,不会执行校验逻辑,自然不会产生对应的违规信息。只有@Size是针对字符串长度的校验,所以仅触发了这一个约束。
解决方案
如果需要对字符串形式的数值做最小值校验,改用@DecimalMin注解,它支持将字符串解析为数值后进行校验。修改后的@Name注解如下:
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention(RUNTIME) @Documented @NotNull @DecimalMin(value = "3") // 替换原@Min注解 @Size(min = 3, max = 30) @Constraint(validatedBy = {}) public @interface Name { String message() default "lms.common.validation.Name.message"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
修改后,传入"12"时,@DecimalMin会将字符串解析为数值并判断是否小于3,同时@Size校验长度,两个约束都会触发违规,测试即可通过。
内容的提问来源于stack exchange,提问作者0xff
相关产品推荐
相关产品推荐

