如何使用Jackson将复杂JSON数组解析为对应Java类?
实现方案
原JSON的dataBlock数组包含多个headingName节点,我们需要将这些节点按其name字段映射到MyResponse的对应属性上,同时保证未来新增heading时的扩展性。可以通过自定义Jackson反序列化器结合通用基类来实现:
1. 定义通用属性类
所有headingName下的attributes结构统一,先创建通用的Attribute类处理多类型的value:
@Data @NoArgsConstructor @AllArgsConstructor public class Attribute { private String name; private String position; // 兼容字符串、数组、对象等多种value类型,后续可按需转换 private Object value; }
2. 定义通用Heading基类
所有具体的Heading类继承该基类,统一包含name、position、attributes字段:
@Data @NoArgsConstructor @AllArgsConstructor public abstract class BaseHeading { private String name; private String position; private List<Attribute> attributes; }
3. 定义具体的Heading类
根据JSON中的name字段创建对应实体类,继承基类即可(后续有特殊字段可直接扩展):
// 对应"name": "Operational Information" @Data @EqualsAndHashCode(callSuper = true) @NoArgsConstructor @AllArgsConstructor public class OperationalInformation extends BaseHeading {} // 对应"name": "CRA" @Data @EqualsAndHashCode(callSuper = true) @NoArgsConstructor @AllArgsConstructor public class CRA extends BaseHeading {}
4. 实现自定义反序列化器
核心逻辑是遍历dataBlock数组,根据headingName的name值映射到MyResponse的对应属性:
public class MyResponseDeserializer extends StdDeserializer<MyResponse> { public MyResponseDeserializer() { super(MyResponse.class); } @Override public MyResponse deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { MyResponse response = new MyResponse(); JsonNode rootNode = p.getCodec().readTree(p); JsonNode dataBlockNode = rootNode.get("dataBlock"); if (dataBlockNode != null && dataBlockNode.isArray()) { ObjectMapper mapper = (ObjectMapper) p.getCodec(); for (JsonNode itemNode : dataBlockNode) { JsonNode headingNode = itemNode.get("headingName"); String headingName = headingNode.get("name").asText(); // 根据headingName匹配对应类,赋值到MyResponse属性 switch (headingName) { case "Operational Information": OperationalInformation info = mapper.treeToValue(headingNode, OperationalInformation.class); response.setOperationalInformation(info); break; case "CRA": CRA cra = mapper.treeToValue(headingNode, CRA.class); response.setCra(cra); break; // 未来新增heading时,添加对应case即可 default: // 可忽略未知heading或做自定义处理 break; } } } return response; } }
5. 配置MyResponse类
在MyResponse上指定自定义反序列化器,保留原有注解:
@Data @Builder @AllArgsConstructor @NoArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) @JsonDeserialize(using = MyResponseDeserializer.class) // 指定自定义反序列化器 public class MyResponse { private OperationalInformation operationalInformation; private CRA cra; // 未来新增heading时,添加对应属性即可 }
6. 测试反序列化
用Jackson验证解析效果:
public class TestDeserialization { public static void main(String[] args) throws IOException { String json = "你的目标JSON字符串"; ObjectMapper mapper = new ObjectMapper(); MyResponse response = mapper.readValue(json, MyResponse.class); // 验证解析结果 System.out.println(response.getOperationalInformation().getName()); System.out.println(((JsonNode)response.getCra().getAttributes().get(1).getValue()).get("line1").asText()); } }
扩展性说明
- 未来新增
headingName时,只需三步:- 创建继承
BaseHeading的实体类; - 在
MyResponse中添加该类的属性; - 在反序列化器的
switch中新增对应case分支。
- 创建继承
- 若某个heading需要特殊结构,直接修改对应实体类即可,不会影响其他模块。
内容的提问来源于stack exchange,提问作者saran3h
相关产品推荐
相关产品推荐

