用Jackson映射嵌套的值
最后修改:9月30日,2020年
1.概述
使用JSON时的典型用例是将从一个模型进行转换到另一个模型。例如,我们可能希望将复杂的密集嵌套的对象图解析为更直接的模型,用于另一个域。
在这篇简短的文章中,我们将看看如何映射嵌套的值杰克逊使复杂的数据结构变平。我们将用三种不同的方式反序列化JSON:
- 使用@JsonProperty
- 使用JsonNode
- 使用自定义JsonDeserializer
进一步阅读:
2.Maven的依赖
让我们首先将以下依赖项添加到pom.xml:
<依赖> < groupId > com.fasterxml.jackson。jackson-databind 2.11.1
我们可以找到最新版本的jackson-databind上Maven中央。
3.JSON源
考虑将下面的JSON作为我们示例的源材料。虽然结构是人为设计的,但请注意我们包含了嵌套两层的属性:
{“ID”:“957C43F2-FA2E-42F9-BF75-6E3D5BB6960A”,“名称”:“最好的产品”,“品牌”:{“ID”:“9BCD817D-0141-42E6-8F04-E5AAAB0980B6”,“名称”,“名称“:”Acme产品“,”所有者“:{”ID“:”B21A80B1-0C09-4BE3-9EBD-EA3653511C13“,”名称“:”Ultimate Corp,Inc。“}}}
4.简化的域模型
在扁平域模型中描述产品类,我们将提取名牌,它嵌套在我们的源JSON的一层深处。同时,我们将提取overname.,它嵌套了两层,并在嵌套内品牌目的:
public class Product {private String id;私人字符串名称;私人字符串名牌;私人字符串ownerName;//标准的getter和setter}
5.映射与注释
要映射嵌套的名牌属性,我们首先需要解包嵌套品牌对象一个地图并提取的名字财产。然后映射overname.,我们解包嵌套所有者对象一个地图并提取其的名字财产。
我们可以指导杰克逊这么做组合使用来解包嵌套属性@JsonProperty以及一些自定义逻辑我们加入我们的产品班级:
public class Product{//…@SuppressWarnings("unchecked") @JsonProperty("brand") private void unpackNested(Map brand);名牌=(字符串)brand.get(“名字”);Map owner = (Map)brand.get("owner");这一点。所有者Name = owner.get("name"); } }
我们的客户端代码现在可以使用objectmap要转换我们的源JSON,它作为字符串常数SOURCE_JSON在测试类中:
@Test public void whenUsingAnnotations_thenOk() throws IOException {Product Product = new objectapper () .readerFor(Product.class) .readValue(SOURCE_JSON);assertEquals(Product . getname(),“最好的产品”);assertequal (product.getBrandName(),“ACME产品”);assertEquals(product.getOwnerName(), "Ultimate Corp, Inc.");}
6.映射与JsonNode
将嵌套的数据结构映射为JsonNode还需要一点功夫。在这里,我们使用objectmap的readTree解析所需的字段:
@Test public void whenUsingJsonNode_thenOk() throws IOException {JsonNode productNode = new objectapper ().readTree(SOURCE_JSON);Product Product = new Product();product.setId (productNode.get (" id ") .textValue ());product.setName (productNode.get(“名字”).textValue ());product.setBrandName (productNode.get(“商标”). get(“名字”).textValue ());product.setOwnerName (productNode.get(“商标”). get(“业主”). get(“名字”).textValue ());assertEquals(Product . getname(),“最好的产品”);assertequal (product.getBrandName(),“ACME产品”);assertEquals(product.getOwnerName(), "Ultimate Corp, Inc.");}
7.使用自定义映射JsonDeserializer
用自定义映射嵌套的数据结构JsonDeserializer与...相同JsonNode方法从实现的角度出发。我们首先创建JsonDeserializer:
公共类ProductDeserializer扩展了StdDeserializer {Public ProductDeserializer(){这个(null);public productDeserializer(类<?> vc){super(vc);@Override公共产品Deserialize(JSONParser JP,DeserializationContext CTXT)抛出IOException,JSONProcessingException {JSONNode ProductNode = jp.getCodec()。ReadTree(JP);Product Product = new Product();product.setId (productNode.get (" id ") .textValue ());product.setName (productNode.get(“名字”).textValue ());product.setBrandName (productNode.get(“商标”). get(“名字”).textValue ());product.setowname(ProductNode.get(“品牌”)。获取(“所有者”).get(“名称”)。TextValue());退货产品;}}
7.1。Deserializer的手动注册
要手动注册我们的自定义Deserializer,我们的客户端代码必须添加JsonDeserializer到A.模块,注册模块与一个objectmap,叫readValue:
@Test公共void whenusingdeserializermanalyregistered_thenok()抛出ioException {objectMapper映射器= new objectMapper();SimpleModule模块=新SimpleModule();module.addeserializer(Product.Class,New ProductDeserializer());Mapper.registerermodule(模块);产品产品= Mapper.ReadValue(Source_JSON,Product.Class);assertEquals(Product . getname(),“最好的产品”);assertequal (product.getBrandName(),“ACME产品”);assertEquals(product.getOwnerName(), "Ultimate Corp, Inc.");}
7.2。自动注册反序列化
作为手工注册的替代方法JsonDeserializer,我们可以直接在课堂上注册Deserializer:
@JsonDeserialize(using = ProductDeserializer.class) public class Product{//…}
通过这种方法,不需要手动注册。让我们来看看我们的客户代码使用自动注册:
@Test public void whenUsingDeserializerAutoRegistered_thenOk() throws IOException {objectapper mapper = new objectapper ();产品产品= Mapper.ReadValue(Source_JSON,Product.Class);assertEquals(Product . getname(),“最好的产品”);assertequal (product.getBrandName(),“ACME产品”);assertEquals(product.getOwnerName(), "Ultimate Corp, Inc.");}
8.结论
在本教程中,我们展示了几种使用方式杰克逊解析包含嵌套值的JSON。看看我们的主杰克逊教程页面中有更多的例子。
并且,一如既往,可以找到代码片段在github上。