使用@JsonUnwrapped时Jackson能否同时支持包装与解包两种JSON输入格式
解决方案
方案1:轻量注解兼容(推荐)
无需编写复杂逻辑,仅需在外层类增加一个专属setter即可同时兼容两种格式,原理是利用@JsonUnwrapped处理解包格式的平级字段,额外新增的@JsonProperty方法处理包装格式的嵌套对象:
// 外层类示例 public class Parent { // 原有注解保留,负责接收解包格式的nested1、nested2字段 @JsonUnwrapped private DataObject dataObject; // 新增setter,仅在反序列化时接收包装格式的dataObject嵌套对象 @JsonProperty(value = "dataObject", access = JsonProperty.Access.WRITE_ONLY) public void setWrappedDataObject(DataObject dataObject) { this.dataObject = dataObject; } // 原有getter、其他属性和方法保持不变 public DataObject getDataObject() { return dataObject; } }
DataObject类无需修改,补充无参构造即可正常使用:
@Getter @NoArgsConstructor // 确保有无参构造供Jackson反序列化 public class DataObject { private String nested1; private String nested2; }
方案2:自定义反序列化器(适合复杂兼容场景)
如果后续还有其他字段的兼容需求,可以通过自定义反序列化器手动判断JSON结构,灵活处理两种格式:
- 首先编写自定义反序列化类:
public class ParentDeserializer extends StdDeserializer<Parent> { public ParentDeserializer() { super(Parent.class); } @Override public Parent deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode rootNode = p.getCodec().readTree(p); ObjectMapper mapper = (ObjectMapper) p.getCodec(); Parent parent = new Parent(); DataObject dataObject; // 识别当前JSON是包装格式还是解包格式 if (rootNode.has("dataObject")) { dataObject = mapper.treeToValue(rootNode.get("dataObject"), DataObject.class); } else { dataObject = mapper.treeToValue(rootNode, DataObject.class); } parent.setDataObject(dataObject); // 外层类其他属性的赋值逻辑可在这里补充 // 示例:parent.setOtherField(rootNode.get("otherField").asText()); return parent; } }
- 给外层类绑定反序列化器:
@JsonDeserialize(using = ParentDeserializer.class) public class Parent { private DataObject dataObject; // 其他属性、getter、setter }
注意事项
- 方案1依赖Jackson 2.6及以上版本,
JsonProperty.Access.WRITE_ONLY为该版本新增特性 - 两种方案都要求DataObject类提供无参构造函数,否则Jackson会抛出反序列化异常
- 默认序列化输出为解包格式,如果需要输出包装格式,仅需去掉外层类的
@JsonUnwrapped注解即可
内容的提问来源于stack exchange,提问作者Peter Kronenberg
相关产品推荐
相关产品推荐

