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

Spring Boot自定义校验注解校验List失效,抛出异常问题排查

自定义Spring Boot校验注解无法校验List集合的问题

我在开发Spring Boot项目时,尝试实现一个自定义校验注解SampleValid,期望能同时校验对象的单个字段和List集合,但当前实现无法正常工作,校验List时会抛出异常,单个对象校验则正常。

自定义注解代码

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = SampleValidator.class)
@Repeatable(SampleValid.List.class)
@Documented
public @interface SampleValid {

    String name() default "name";

    String message() default "";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface List {
        SampleValid[] value();
    }
}

校验器代码

public class SampleValidator implements ConstraintValidator<SampleValid, Object> {
        private String fieldName;
    
        public void initialize(SampleValid constraintAnnotation) {
            fieldName = constraintAnnotation.name();
        }
    
        public boolean isValid(Object value, ConstraintValidatorContext context) {
            if (value == null) return true;
    
            try {
                String fieldValue = BeanUtils.getProperty(value, fieldName);
    
                if (/* 这里是你的校验逻辑 */) {
                    context.disableDefaultConstraintViolation();
                    context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
                            .addConstraintViolation();
                    return false;
                }
            } catch (Exception ex) {
                return false;
            }
    
            return true;
        }
    }

使用示例与报错

@SampleValid
private List<SomeObject> someObjects; // 此用法报错

@SampleValid
private SomeObject someObject; // 此用法正常

报错信息:

java.lang.NoSuchMethodException: Unknown property 'name' on class 'class java.util.ArrayList'


问题原因

  • 当注解标注在List字段上时,校验器接收的value是ArrayList实例,而你的校验逻辑直接调用BeanUtils.getProperty(value, fieldName)尝试获取name属性,但ArrayList本身并没有这个属性,因此抛出异常。
  • 当前校验器没有区分单个对象和集合类型,默认将所有传入值当作单个对象处理,没有遍历集合内的元素进行逐个校验。

修复方案

修改SampleValidator的isValid方法,先判断传入值是否为集合/数组类型,若是则遍历每个元素执行校验逻辑;若为单个对象则直接校验:

public class SampleValidator implements ConstraintValidator<SampleValid, Object> {
    private String fieldName;

    public void initialize(SampleValid constraintAnnotation) {
        fieldName = constraintAnnotation.name();
    }

    public boolean isValid(Object value, ConstraintValidatorContext context) {
        if (value == null) return true;

        // 处理集合/数组类型
        if (value instanceof Collection) {
            Collection<?> collection = (Collection<?>) value;
            for (Object element : collection) {
                if (!validateSingleElement(element, context)) {
                    return false;
                }
            }
        } else if (value.getClass().isArray()) {
            Object[] array = (Object[]) value;
            for (Object element : array) {
                if (!validateSingleElement(element, context)) {
                    return false;
                }
            }
        } else {
            // 处理单个对象
            return validateSingleElement(value, context);
        }
        return true;
    }

    // 抽取单个对象的校验逻辑
    private boolean validateSingleElement(Object element, ConstraintValidatorContext context) {
        if (element == null) return true;
        try {
            String fieldValue = BeanUtils.getProperty(element, fieldName);

            if (/* 这里替换为你的实际校验逻辑 */) {
                context.disableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
                        .addConstraintViolation();
                return false;
            }
        } catch (Exception ex) {
            return false;
        }
        return true;
    }
}

内容的提问来源于stack exchange,提问作者H Athukorala

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 17:15:34