You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 07:57:25