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

Spring Validator中ValidationUtils工具方法工作原理及报错解决

Spring Validator 使用问题咨询

场景代码

@Component("singerValidator")
public class SingerValidator implements Validator {
  @Override
  public boolean supports(Class<?> clazz) {
    return Singer.class.equals(clazz);
  }

  @Override
  public void validate(Object target, Errors errors) {
    ValidationUtils.rejectIfEmpty(errors, "firstName", "firstName.empty");
  }
}

运行错误信息

Exception in thread "main" org.springframework.beans.NotReadablePropertyException: Invalid property 'firstName' of bean class [com.example.spring.tutorial.demo.ch10.validators.SingerValidator]: Bean property 'firstName' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:627)
at org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:617)
at org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:105)
at org.springframework.validation.AbstractBindingResult.getFieldValue(AbstractBindingResult.java:225)
at org.springframework.validation.ValidationUtils.rejectIfEmpty(ValidationUtils.java:172)
at org.springframework.validation.ValidationUtils.rejectIfEmpty(ValidationUtils.java:115)
at com.example.spring.tutorial.demo.ch10.validators.SingerValidator.validate(SingerValidator.java:18)
at org.springframework.validation.ValidationUtils.invokeValidator(ValidationUtils.java:89)
at org.springframework.validation.ValidationUtils.invokeValidator(ValidationUtils.java:56)
at com.example.spring.tutorial.demo.ch10.Demo.main(Demo.java:28)

疑问

错误提示SingerValidator类没有firstName属性的getter方法,但该字段实际定义在Singer类中,现咨询:

  1. ValidationUtils.rejectIfEmpty不接收target参数是如何工作的?
  2. 如何修复这段代码?
  3. 我遗漏了什么?

问题解答

1. ValidationUtils.rejectIfEmpty的工作逻辑

ValidationUtils.rejectIfEmpty无需显式传入target,是因为Errors对象内部已经绑定了待校验的目标实例。当创建Errors实现类(比如BeanPropertyBindingResult)时,必须传入要校验的对象,Errors会持有该对象的引用。调用ValidationUtils的校验方法时,工具类会通过Errors获取到目标对象,再通过反射读取指定字段的值,判断是否为空并触发错误提示。

2. 代码修复方案

报错的核心原因是调用校验时传入的目标对象错误——把SingerValidator实例当成了被校验对象传入,而不是Singer实体类实例。

正确的校验调用示例:

// 1. 创建待校验的Singer实例
Singer singer = new Singer();
// 2. 创建Errors对象,绑定目标实例
Errors errors = new BeanPropertyBindingResult(singer, "singer");
// 3. 获取校验器实例(从Spring容器或直接实例化)
SingerValidator validator = context.getBean(SingerValidator.class);
// 4. 执行校验:传入正确的target(singer)和errors
ValidationUtils.invokeValidator(validator, singer, errors);

// 或者直接调用校验器的validate方法
validator.validate(singer, errors);

检查Demo.java第28行,确认invokeValidator的第二个参数是Singer实例,而非SingerValidator本身。

3. 遗漏的核心点

  • 混淆了校验器与被校验对象:错误地将校验器自身作为校验目标传入,导致Spring在校验器类中查找firstName字段,自然无法找到。
  • 对Errors的绑定逻辑不清晰:Errors必须与待校验的实体对象绑定,ValidationUtils的所有校验操作都依赖Errors来获取目标对象的字段值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 14:07:28