父子POJO结合@RequestBody使用异常:父类字段未被赋值
解决Spring Controller接收子类对象时父类字段未赋值的问题
在Spring项目中定义了父类CommonInfo和子类JavaDeveloper(继承自CommonInfo),通过Controller的@RequestBody接收子类对象时,传入包含父子类字段的JSON请求体,仅子类字段能被正确赋值,父类字段始终为空。
相关代码
父类CommonInfo
@JsonIgnoreProperties(ignoreUnknown = true) public class CommonInfo { @NotNull(message = "name is mandatory") String name; @NotNull(message = "pan is mandatory") String pan; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPan() { return pan; } public void setPan(String pan) { this.pan = pan; } }
子类JavaDeveloper
@JsonIgnoreProperties(ignoreUnknown = true) public class JavaDeveloper extends CommonInfo{ @NotNull(message = "currentPoject is mandatory") String currentPoject; @NotNull(message = "timeline is mandatory") String timeline; public String getCurrentPoject() { return currentPoject; } public void setCurrentPoject(String currentPoject) { this.currentPoject = currentPoject; } public String getTimeline() { return timeline; } public void setTimeline(String timeline) { this.timeline = timeline; } }
Controller代码
@RequestMapping(value = "/createUser", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponsePacket createJavaDeveloper(@Valid @RequestBody JavaDeveloper requestPacket) { return new ResponsePacket(); }
JSON请求体
{ "name" : "Smith", "pan" : "DFREW1243E", "currentPoject" : "Banking project", "timeline" : "13-04-2023" }
问题原因
核心原因是Jackson在反序列化继承类时,无法识别父类中包私有访问权限的字段。虽然父类提供了public的getter和setter方法,但Jackson默认的字段访问策略会优先尝试直接访问字段,而包私有字段只能被同一包内的类访问,若子类与父类不在同一包下,Jackson就无法直接读写这些字段,导致父类字段无法被赋值。
解决方案
方案一:给父类字段添加@JsonProperty注解
通过@JsonProperty注解明确指定字段对应的JSON键名,强制Jackson通过getter/setter方法处理字段,而非直接访问字段本身。修改后的父类代码如下:
@JsonIgnoreProperties(ignoreUnknown = true) public class CommonInfo { @JsonProperty @NotNull(message = "name is mandatory") String name; @JsonProperty @NotNull(message = "pan is mandatory") String pan; // getter和setter方法保持不变 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPan() { return pan; } public void setPan(String pan) { this.pan = pan; } }
方案二:修改父类字段的访问权限为public
将父类的name和pan字段改为public访问权限,让Jackson可以直接访问这些字段:
@JsonIgnoreProperties(ignoreUnknown = true) public class CommonInfo { @NotNull(message = "name is mandatory") public String name; @NotNull(message = "pan is mandatory") public String pan; // getter和setter方法可保留或移除,视需求而定 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPan() { return pan; } public void setPan(String pan) { this.pan = pan; } }
方案三:全局配置Jackson的字段访问策略
通过Spring配置类全局设置Jackson的字段访问策略,使其优先使用setter方法进行反序列化:
@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); // 设置字段访问策略为仅通过getter/setter方法访问 objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.NONE); objectMapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.PUBLIC_ONLY); objectMapper.setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.PUBLIC_ONLY); return objectMapper; } }
内容的提问来源于stack exchange,提问作者Intekhab Alam
相关产品推荐
相关产品推荐

