Java 使用 Jackson 将嵌套数组反序列化为 ArrayList
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27895376/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Deserialize nested array as ArrayList with Hymanson
提问by Dmitry
I have a piece of JSON, that looks like this:
我有一段 JSON,看起来像这样:
{
"authors": {
"author": [
{
"given-name": "Adrienne H.",
"surname": "Kovacs"
},
{
"given-name": "Philip",
"surname": "Moons"
}
]
}
}
I have created a class to store Author information:
我创建了一个类来存储作者信息:
public class Author {
@JsonProperty("given-name")
public String givenName;
public String surname;
}
And two wrapper classes:
和两个包装类:
public class Authors {
public List<Author> author;
}
public class Response {
public Authors authors;
}
This is working, but having two wrapper classes seems to be unnecessary. I want to find a way to remove Authors
class and have a list as a property of Entry class. Is something like that is possible with Hymanson?
这是有效的,但似乎没有必要拥有两个包装类。我想找到一种方法来删除Authors
类并将列表作为 Entry 类的属性。Hyman逊有可能做到吗?
Update
更新
Solved that with custom deserializer:
用自定义解串器解决了这个问题:
public class AuthorArrayDeserializer extends JsonDeserializer<List<Author>> {
private static final String AUTHOR = "author";
private static final ObjectMapper mapper = new ObjectMapper();
private static final CollectionType collectionType =
TypeFactory
.defaultInstance()
.constructCollectionType(List.class, Author.class);
@Override
public List<Author> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
throws IOException, JsonProcessingException {
ObjectNode objectNode = mapper.readTree(jsonParser);
JsonNode nodeAuthors = objectNode.get(AUTHOR);
if (null == nodeAuthors // if no author node could be found
|| !nodeAuthors.isArray() // or author node is not an array
|| !nodeAuthors.elements().hasNext()) // or author node doesn't contain any authors
return null;
return mapper.reader(collectionType).readValue(nodeAuthors);
}
}
And using it like this:
并像这样使用它:
@JsonDeserialize(using = AuthorArrayDeserializer.class)
public void setAuthors(List<Author> authors) {
this.authors = authors;
}
Thanks @wassgren for the idea.
感谢@wassgren 的想法。
采纳答案by wassgren
I see at least two approaches to do this if you want to get rid of wrapper classes. The first is to use the Hymanson Tree Model (JsonNode
) and the second is to use a deserialization feature called UNWRAP_ROOT_VALUE
.
如果您想摆脱包装类,我看到至少有两种方法可以做到这一点。第一个是使用 Hymanson Tree Model( JsonNode
),第二个是使用名为UNWRAP_ROOT_VALUE
.
Alternative 1: Use JsonNode
备选方案 1:使用 JsonNode
When deserializing JSON using Hymanson there are multiple ways to control what type of objects that are to be created. The ObjectMapper
can deserialize the JSON to e.g. a Map
, JsonNode
(via the readTree
-method) or a POJO.
使用 Hymanson 反序列化 JSON 时,有多种方法可以控制要创建的对象类型。所述ObjectMapper
可反序列化JSON来例如Map
,JsonNode
(通过readTree
-method)或POJO。
If you combine the readTree
-method with the POJO
conversion the wrappers can be completely removed. Example:
如果将readTree
-method 与POJO
转换结合使用,则可以完全删除包装器。例子:
// The author class (a bit cleaned up)
public class Author {
private final String givenName;
private final String surname;
@JsonCreator
public Author(
@JsonProperty("given-name") final String givenName,
@JsonProperty("surname") final String surname) {
this.givenName = givenName;
this.surname = surname;
}
public String getGivenName() {
return givenName;
}
public String getSurname() {
return surname;
}
}
The deserialization can then look something like this:
然后反序列化看起来像这样:
// The JSON
final String json = "{\"authors\":{\"author\":[{\"given-name\":\"AdrienneH.\",\"surname\":\"Kovacs\"},{\"given-name\":\"Philip\",\"surname\":\"Moons\"}]}}";
ObjectMapper mapper = new ObjectMapper();
// Read the response as a tree model
final JsonNode response = mapper.readTree(json).path("authors").path("author");
// Create the collection type (since it is a collection of Authors)
final CollectionType collectionType =
TypeFactory
.defaultInstance()
.constructCollectionType(List.class, Author.class);
// Convert the tree model to the collection (of Author-objects)
List<Author> authors = mapper.reader(collectionType).readValue(response);
// Now the authors-list is ready to use...
If you use this Tree Model-approach the wrapper classes can be completely removed.
如果您使用此树模型方法,则可以完全删除包装类。
Alternative 2: remove one of the wrappers and unwrap the root valueThe second approach is to remove only one of the wrappers. Assume that you remove the Authors
class but keep the Response
-wrapper. If you add the a @JsonRootName
-annotation you can later unwrap the top-level name.
备选方案 2:移除一个包装器并解开根值第二种方法是仅移除一个包装器。假设您删除了Authors
类但保留了Response
-wrapper。如果您添加 a @JsonRootName
-annotation,您可以稍后解开顶级名称。
@JsonRootName("authors") // This is new compared to your example
public class Response {
private final List<Author> authors;
@JsonCreator
public Response(@JsonProperty("author") final List<Author> authors) {
this.authors = authors;
}
@JsonProperty("author")
public List<Author> getAuthors() {
return authors;
}
}
Then, for your mapper simply use:
然后,对于您的映射器,只需使用:
ObjectMapper mapper = new ObjectMapper();
// Unwrap the root value i.e. the "authors"
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
final Response responsePojo = mapper.readValue(json, Response.class);
The second approach only removes one of the wrapper classes but instead the parsing function is quite pretty.
第二种方法只删除一个包装类,但解析函数非常漂亮。