0

0

如何利用反射实现通用的对象校验框架_多规则链式匹配

P粉602998670

P粉602998670

发布时间:2026-02-12 16:45:27

|

828人浏览过

|

来源于php中文网

原创

必须用getdeclaredfields()并设setaccessible(true)才能获取private字段;校验注解须加在字段而非getter上;继承需递归遍历父类;kotlin字段名可能被重命名;group和payload需显式传递;constraintvalidator泛型不可省略;@valid必须显式标注才启用级联校验。

如何利用反射实现通用的对象校验框架_多规则链式匹配

反射获取字段和注解时,getDeclaredFields()getFields() 别混用

校验框架第一步是扫字段,但很多人一上来就用 getFields(),结果 private 字段全丢了——它只返回 public 成员。必须用 getDeclaredFields(),再手动设 setAccessible(true) 才能读 private 字段值。

常见错误现象:NullPointerException 或校验跳过某些字段,实际是字段根本没被扫描到。

  • 所有校验注解(如 @NotNull@Min)都该加在字段上,不是 getter 方法上,否则反射取不到值
  • 如果类有继承,getDeclaredFields() 不会返回父类字段,得递归调用 getSuperclass() 向上遍历
  • 注意 Kotlin 编译后字段名可能带 $ 或重命名(如 namename$delegate),Java 反射直接按源码名取会失败

规则链执行顺序依赖注解的 groupspayload,但多数人忽略验证上下文传递

所谓“链式匹配”,不是硬编码 if-else,而是靠注解元信息动态组装规则链。比如 @NotBlank(groups = Create.class)@NotBlank(groups = Update.class) 必须在触发校验时显式传入 group 类型,否则默认不生效。

使用场景:同一对象在创建和更新时校验逻辑不同,靠 group 分离规则,而不是写两套校验器。

Knowt
Knowt

Knowt是一款AI驱动的在线学习工具

下载
  • 调用 validator.validate(target, Create.class) 才会命中 Create.class 组的规则;漏传参数等于白标注解
  • payload 通常用于携带自定义校验上下文(如租户 ID、业务通道),但标准 Validator 不解析它,得自己在 ConstraintValidator 实现里从 ConstraintValidatorContext 提取
  • 多个注解在同一字段上时,执行顺序由 JVM 返回的注解数组顺序决定,不保证声明顺序,别依赖“先写哪个就先校验”

自定义 ConstraintValidator 里拿不到运行时值?检查 initialize() 是否覆盖了泛型参数

写一个 CheckInListValidator 校验字段是否在枚举白名单里,结果 isValid()value 总是 null——大概率是 initialize() 方法签名写成了 initialize(CheckInList constraintAnnotation),而没继承泛型父类。

正确写法必须显式声明泛型类型,否则运行时擦除导致约束注解实例为空:

public class CheckInListValidator implements ConstraintValidator<CheckInList, String> {
    private String[] allowedValues;

    @Override
    public void initialize(CheckInList constraintAnnotation) {
        this.allowedValues = constraintAnnotation.value(); // 这里才能取到注解属性
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return value != null && Arrays.asList(allowedValues).contains(value);
    }
}
  • 忘写 implements ConstraintValidator<xxx yyy></xxx> 中的泛型,initialize() 参数就是 raw type,反射取不到注解值
  • 如果校验逻辑涉及 Spring Bean(如查数据库),不能在 ConstraintValidator 里直接 @Autowired,得通过 ValidationConfiguration 注入或用 ApplicationContext.getBean()
  • 性能影响:每次校验都会 new 一个 validator 实例,所以 initialize() 里适合做一次性的配置解析,别放耗时操作

嵌套对象校验失效?@Valid 必须显式标注,且不能只靠级联

用户对象里有个 Address address 字段,Address 类也有 @NotBlank 注解,但改了 address.street 为 null 却没报错——因为没在 address 字段上加 @Valid

JSR-303 的级联校验不是默认开启的,必须主动标注,而且只对字段/方法有效,对集合元素要配合 @Valid + @Size 等组合使用。

  • @Valid 只作用于当前字段,不会自动递归进 List 的每个元素;List 校验需写成 List(Java 8+ type annotation)或用 @Valid 配合 @Size 在字段上
  • Map 的 value 校验同理,Map<string user></string> 才行;key 不支持 @Valid
  • Spring MVC 里 Controller 参数用 @Valid,但嵌套对象仍需字段级 @Valid,两者缺一不可
反射做通用校验,最麻烦的从来不是怎么扫字段,而是怎么让注解元数据、运行时值、上下文环境三者对齐。少设一个 groups、漏标一个 @Valid、或者泛型擦除没处理好,整条链就静默失效——它不会报错,只会假装校验过了。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Kotlin协程编程与Spring Boot集成实践
Kotlin协程编程与Spring Boot集成实践

本专题围绕 Kotlin 协程机制展开,深入讲解挂起函数、协程作用域、结构化并发与异常处理机制,并结合 Spring Boot 展示协程在后端开发中的实际应用。内容涵盖异步接口设计、数据库调用优化、线程资源管理以及性能调优策略,帮助开发者构建更加简洁高效的 Kotlin 后端服务架构。

27

2026.02.12

golang如何定义变量
golang如何定义变量

golang定义变量的方法:1、声明变量并赋予初始值“var age int =值”;2、声明变量但不赋初始值“var age int”;3、使用短变量声明“age :=值”等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

206

2024.02.23

golang有哪些数据转换方法
golang有哪些数据转换方法

golang数据转换方法:1、类型转换操作符;2、类型断言;3、字符串和数字之间的转换;4、JSON序列化和反序列化;5、使用标准库进行数据转换;6、使用第三方库进行数据转换;7、自定义数据转换函数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

235

2024.02.23

golang常用库有哪些
golang常用库有哪些

golang常用库有:1、标准库;2、字符串处理库;3、网络库;4、加密库;5、压缩库;6、xml和json解析库;7、日期和时间库;8、数据库操作库;9、文件操作库;10、图像处理库。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

346

2024.02.23

golang和python的区别是什么
golang和python的区别是什么

golang和python的区别是:1、golang是一种编译型语言,而python是一种解释型语言;2、golang天生支持并发编程,而python对并发与并行的支持相对较弱等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

212

2024.03.05

golang是免费的吗
golang是免费的吗

golang是免费的。golang是google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的开源编程语言,采用bsd开源协议。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

402

2024.05.21

golang结构体相关大全
golang结构体相关大全

本专题整合了golang结构体相关大全,想了解更多内容,请阅读专题下面的文章。

322

2025.06.09

golang相关判断方法
golang相关判断方法

本专题整合了golang相关判断方法,想了解更详细的相关内容,请阅读下面的文章。

197

2025.06.10

2026春节习俗大全
2026春节习俗大全

本专题整合了2026春节习俗大全,阅读专题下面的文章了解更多详细内容。

189

2026.02.11

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号