Spring控制器继承下@RequestBody反序列化失败与ObjectMapper配置问题
问题产生原因
- 泛型类型擦除导致Spring MVC无法正确解析@RequestBody参数的实际类型:父类
BaseController中定义的saveVersion方法的@RequestBody V version参数,默认会因为泛型擦除被Spring解析为上界DocumentVersion,极端场景下会直接擦除为Object类型,导致Jackson的多态处理逻辑无法正确触发。 - Jackson可见性配置不匹配:你自定义的
getType()方法是private权限,且DietVersion中没有提供public的setType()方法,虽然你设置了visible = true允许type字段作为普通属性反序列化,但Jackson默认只会处理public的字段/存取方法,无法正确读取请求中的type字段,多态逻辑失效后会出现反序列化结果为空的问题。 - 多态标识处理冲突:手动写的固定返回值的
getType()方法和@JsonTypeInfo的自动识别逻辑冲突,会干扰Jackson对多态类型的判断。
解决方案
修复多态标识相关代码
优先删除DietVersion中手动定义的private getType()方法,@JsonTypeInfo会自动从请求JSON中读取type字段完成多态类型匹配,不需要手动提供固定返回值的getter。如果需要保留type作为实体类属性,补充对应的public存取方法:
public String getType() { return "diet"; } public void setType(String type) { // 可空实现,因为实际类型固定为diet }
解决泛型擦除问题
两种方案二选一即可:
- 在
DocumentVersion的实现类上添加@JsonDeserialize注解直接指定反序列化目标类,绕过泛型擦除的影响:
@Data @JsonDeserialize(as = DietVersion.class) public class DietVersion implements DocumentVersion { // 原有属性代码 }
- 在子类重写的
saveVersion方法上重新标注@RequestBody注解,让Spring正确识别实际参数类型:
@Override public void saveVersion(@PathVariable("docId") String docId, @RequestBody DietVersion version, Authentication authentication) { super.saveVersion(docId, version, authentication); }
调整ObjectMapper配置
如果上述修改后仍然存在属性为空的问题,自定义ObjectMapper配置,开启私有字段访问权限:
@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); // 允许访问私有字段,无需依赖getter/setter完成反序列化 objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); // 忽略请求中的未知属性,避免反序列化报错 objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 如果用到了JSR310时间类型(LocalDate、LocalDateTime等)注册对应序列化模块 objectMapper.registerModule(new JavaTimeModule()); return objectMapper; } }
Spring Boot项目也可以直接在配置文件中修改:
spring: jackson: visibility: field: any deserialization: fail-on-unknown-properties: false
内容的提问来源于stack exchange,提问作者Programmer
相关产品推荐
相关产品推荐

