@JsonIgnoreProperties无法忽略@Validateable隐式Errors致Jackson反序列化失败
标注grails.validation.Validateable注解的类会被框架隐式注入errors对象,调用com.fasterxml.jackson.databind.ObjectMapper.readValue(myJson)反序列化该类实例时抛出异常:
Cannot construct instance of org.springframework.validation.Errors (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
已尝试的无效操作:
- 在目标类添加
@JsonIgnoreProperties(["errors", "Errors"])注解,同时开启ignoreUnknown = true配置,异常仍触发 - 在类中显式声明
Errors errors成员变量并添加@JsonIgnore注解,试图将隐式属性转为显式属性实现忽略,未生效
核心约束:不允许修改ObjectMapper全局属性忽略规则。
Grails通过AST动态织入的方式给@Validateable类添加errors属性、对应的getErrors()/setErrors()方法,这些成员不是类源码中显式声明的内容:标记在字段上的@JsonIgnore、基于显式属性扫描的@JsonIgnoreProperties都无法匹配到动态织入的getter方法,因此忽略规则不生效。Jackson默认会将所有public getter识别为待处理属性,因此会尝试实例化抽象类型Errors触发报错。
方案1:类级别MixIn绑定(侵入性最低,推荐)
不需要修改全局ObjectMapper配置,仅针对目标Validateable类关联混编注解,直接匹配动态织入的getter方法实现忽略:
- 定义MixIn接口,标记要忽略的getter:
import com.fasterxml.jackson.annotation.JsonIgnore; import org.springframework.validation.Errors; public interface ValidateableErrorsMixIn { @JsonIgnore Errors getErrors(); } - 反序列化前,仅给当前使用的ObjectMapper实例添加目标类的MixIn绑定,不影响其他类的处理逻辑:
ObjectMapper mapper = new ObjectMapper(); // 仅对指定的Validateable类生效,非全局配置 mapper.addMixIn(YourValidateableClass.class, ValidateableErrorsMixIn.class); YourValidateableClass result = mapper.readValue(myJson, YourValidateableClass.class);
方案2:修改目标类的Jackson属性检测规则
直接在目标Validateable类上添加注解,调整Jackson对该类的属性识别范围,自动跳过非显式声明的织入属性:
import com.fasterxml.jackson.annotation.JsonAutoDetect import grails.validation.Validateable import static com.fasterxml.jackson.annotation.PropertyAccessor.* @Validateable @JsonAutoDetect( fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE ) class YourBizClass { // 业务字段按原有逻辑声明即可 }
如果业务类本身依赖getter/setter承载属性,可以单独调整可见性规则,只保留业务需要的getter检测即可,该配置为类级别,完全不影响ObjectMapper全局配置。
方案3:定向属性过滤(适合批量处理所有Validateable类)
如果项目中存在大量@Validateable类需要处理,可以给ObjectMapper注册仅针对Validateable类型生效的属性过滤器,不需要修改全局忽略配置:
ObjectMapper mapper = new ObjectMapper() mapper.serializerFactory = mapper.serializerFactory.withModifier(new BeanSerializerModifier() { @Override List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) { // 仅对标注了Validateable注解的类过滤errors属性 if (beanDesc.classAnnotations.has(Validateable.class)) { return beanProperties.findAll { it.name != "errors" } } return beanProperties } })
该逻辑只会在识别到类带@Validateable注解时移除errors属性的处理逻辑,其余类的序列化、反序列化行为完全不受影响。
内容的提问来源于stack exchange,提问作者Ev0oD

