如何使用抽象 class 将 JSON 数据数组反序列化为 POJO?
How do I deserialize an array of JSON data into a POJO using an abstract class?
我正在尝试将一些 JSON 映射到 pojo 中。我已经看到如何使用实际数据中的信息来做到这一点,但就我而言,我真的没有任何东西可以识别数据有何不同,但我知道列表是由什么组成的。在下面的示例中,我可能会得到一份囚犯或建筑物的列表,但在这种情况下,我知道我得到的是一份囚犯列表。
我得到下面的JSON(我知道嵌套的数据很奇怪,但我得到的是JSON,我无法控制超过它。)
{
"data": [{
"data": {
"create_date": "2015-09-30",
"building": "12",
"dob": "2/11/1965",
"gender": "M",
"location": {
"zip": "10459"
},
"name": {
"first": "James",
"last": "Bond"
},
"id": "45"
},
"uri": "/prisoner/45"
}, {
"data": {
"create_date": "2015-09-27",
"building": "12",
"dob": "12/15/1985",
"gender": "M",
"location": {
"zip": "10459"
},
"name": {
"first": "Hans",
"last": "Gruber"
},
"id": "56"
},
"uri": "/prisoner/56"
}],
"totals": {
"total": 2,
"page": 1
},
"links": [{
"uri": "/prisoners?limit=2"
}]
}
我有一个 Data 对象,其中包含一个总计对象和一个链接对象。我还有一个包含嵌套的 Data 对象数组的 Datum 对象的集合(在本例中为列表)。 Datum 对象有一个 Thing 抽象 class 和一个 Uri 字符串。我有一个 Prisoner 和一个 Building class 扩展 Thing。在上面JSON,我知道我得到了一份囚犯名单。
我当前的代码:
ObjectMapper mapper = new ObjectMapper();
Data data = mapper.readValue(responseJSON.toString(), Data.class);
如果我进入 Datum 并将 Thing 对象更改为 Prisoner 对象,它工作得很好。我的问题是如何让它接受 Prisoner 或 Building 但仍然有抽象的 Thing class 到位,或者至少让它更通用。我知道我可以制作多个 Datum classes,但我相信一定有办法拥有 1 个 Datum class。实际上,我可以获得数十种不同的数据可能性,而不仅仅是我示例中的 2 个。
您的意思是,您知道读取值时 Thing 的类型是什么?因为在那种情况下,您可以参数化 Data(即 Data<T extends Thing>
),并将类型参数传播到 Datum 以指定您拥有的 Thing 的子类。然后你需要在调用 readValue 时告诉 Jackson 参数化类型,这可以像这样静态地完成:
mapper.readValue(jsonString, new TypeReference<Data<Prisoner>>(){});
这可以通过使用 ObjectMapper 中可用的 TypeFactory 构造参数化类型来动态完成。类似于:
mapper.readValue("", mapper.getTypeFactory()
.constructParametricType(Data.class, thingSubclass));
我正在尝试将一些 JSON 映射到 pojo 中。我已经看到如何使用实际数据中的信息来做到这一点,但就我而言,我真的没有任何东西可以识别数据有何不同,但我知道列表是由什么组成的。在下面的示例中,我可能会得到一份囚犯或建筑物的列表,但在这种情况下,我知道我得到的是一份囚犯列表。
我得到下面的JSON(我知道嵌套的数据很奇怪,但我得到的是JSON,我无法控制超过它。)
{
"data": [{
"data": {
"create_date": "2015-09-30",
"building": "12",
"dob": "2/11/1965",
"gender": "M",
"location": {
"zip": "10459"
},
"name": {
"first": "James",
"last": "Bond"
},
"id": "45"
},
"uri": "/prisoner/45"
}, {
"data": {
"create_date": "2015-09-27",
"building": "12",
"dob": "12/15/1985",
"gender": "M",
"location": {
"zip": "10459"
},
"name": {
"first": "Hans",
"last": "Gruber"
},
"id": "56"
},
"uri": "/prisoner/56"
}],
"totals": {
"total": 2,
"page": 1
},
"links": [{
"uri": "/prisoners?limit=2"
}]
}
我有一个 Data 对象,其中包含一个总计对象和一个链接对象。我还有一个包含嵌套的 Data 对象数组的 Datum 对象的集合(在本例中为列表)。 Datum 对象有一个 Thing 抽象 class 和一个 Uri 字符串。我有一个 Prisoner 和一个 Building class 扩展 Thing。在上面JSON,我知道我得到了一份囚犯名单。
我当前的代码:
ObjectMapper mapper = new ObjectMapper();
Data data = mapper.readValue(responseJSON.toString(), Data.class);
如果我进入 Datum 并将 Thing 对象更改为 Prisoner 对象,它工作得很好。我的问题是如何让它接受 Prisoner 或 Building 但仍然有抽象的 Thing class 到位,或者至少让它更通用。我知道我可以制作多个 Datum classes,但我相信一定有办法拥有 1 个 Datum class。实际上,我可以获得数十种不同的数据可能性,而不仅仅是我示例中的 2 个。
您的意思是,您知道读取值时 Thing 的类型是什么?因为在那种情况下,您可以参数化 Data(即 Data<T extends Thing>
),并将类型参数传播到 Datum 以指定您拥有的 Thing 的子类。然后你需要在调用 readValue 时告诉 Jackson 参数化类型,这可以像这样静态地完成:
mapper.readValue(jsonString, new TypeReference<Data<Prisoner>>(){});
这可以通过使用 ObjectMapper 中可用的 TypeFactory 构造参数化类型来动态完成。类似于:
mapper.readValue("", mapper.getTypeFactory()
.constructParametricType(Data.class, thingSubclass));