Protobuf生成的Java对象使用Hibernate Validator级联校验失效问题
问题根因
该问题是Protobuf生成Java类的特性与Hibernate Validator的默认校验逻辑不兼容导致的,核心原因有两点:
- Protobuf 3 生成的嵌套消息字段的
getXxx()方法永远不会返回null:即便是没有主动赋值的字段,调用getter也会返回一个全默认值的空实例,主动赋值的场景下这一点不会直接导致校验失效。 - 你使用的getter级约束映射,在处理Protobuf生成的类时存在两个匹配障碍:首先Protobuf生成的所有消息类都是final类型,旧版本Hibernate Validator默认会限制final类的级联校验;其次所有Protobuf消息类都继承自
GeneratedMessageV3/GeneratedMessage公共父类,Validator默认的类型匹配逻辑会优先匹配父类规则,找不到对应约束就会跳过级联校验,普通POJO没有父类干扰所以可以正常匹配到你注册的子类约束。
解决方案
以下两种方案亲测有效,可任选其一:
方案1:改用字段级约束映射
Protobuf生成的类的私有字段名和proto定义的字段名一一对应(通常后缀带下划线,可直接查看生成的类源码确认),直接配置字段级的约束即可正常触发级联:
configuration.createConstraintMapping() .type(Car.class) // 示例中字段名是driver_,实际以生成的Car类源码中的字段名为准 .field("driver_") .valid() .field("manufacturer_") .constraint(new NotEmptyDef()) .type(Driver.class) .field("name_") .constraint(new NotEmptyDef());
方案2:显式配置Validator兼容Protobuf类
如果你要保留getter级的映射逻辑,只需要在构建ValidatorFactory时添加如下配置即可:
ValidatorFactory factory = configuration // 允许final类型的Protobuf生成类参与级联校验 .addProperty("hibernate.validator.allow_final_types_as_cascaded", "true") // 显式指定你需要校验的Protobuf类所在的包前缀,避免Validator跳过非Java Bean标准类 .addProperty("hibernate.validator.packages", "com.mycompany") .buildValidatorFactory();
内容的提问来源于stack exchange,提问作者Drazen Nikolic
相关产品推荐
相关产品推荐

