使用 Jackson 将嵌套数组反序列化为 ArrayList
Posted
技术标签:
【中文标题】使用 Jackson 将嵌套数组反序列化为 ArrayList【英文标题】:Deserialize nested array as ArrayList with Jackson 【发布时间】:2015-03-09 19:53:45 【问题描述】:我有一段 JSON,看起来像这样:
"authors":
"author": [
"given-name": "Adrienne H.",
"surname": "Kovacs"
,
"given-name": "Philip",
"surname": "Moons"
]
我创建了一个类来存储作者信息:
public class Author
@JsonProperty("given-name")
public String givenName;
public String surname;
还有两个包装类:
public class Authors
public List<Author> author;
public class Response
public Authors authors;
这是可行的,但似乎没有必要拥有两个包装类。我想找到一种方法来删除 Authors
类并将列表作为 Entry 类的属性。杰克逊可以做到这样的事情吗?
更新
使用自定义反序列化器解决了这个问题:
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);
并像这样使用它:
@JsonDeserialize(using = AuthorArrayDeserializer.class)
public void setAuthors(List<Author> authors)
this.authors = authors;
感谢@wassgren 的想法。
【问题讨论】:
回答对你有帮助 【参考方案1】:如果您想摆脱包装类,我看到至少有两种方法可以做到这一点。第一种是使用杰克逊树模型(JsonNode
),第二种是使用称为UNWRAP_ROOT_VALUE
的反序列化功能。
备选方案 1:使用 JsonNode
使用 Jackson 反序列化 JSON 时,有多种方法可以控制要创建的对象类型。 ObjectMapper
可以将 JSON 反序列化为例如Map
、JsonNode
(通过readTree
-方法)或 POJO。
如果将readTree
方法与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 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...
如果您使用这种树模型方法,则可以完全删除包装类。
备选方案 2:移除其中一个包装器并解开根值
第二种方法是只删除一个包装器。假设您删除了 Authors
类,但保留了 Response
-wrapper。如果您添加 @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;
然后,您的映射器只需使用:
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);
第二种方法只删除了一个包装类,但解析功能相当漂亮。
【讨论】:
我使用了 Alternative 2,效果很好以上是关于使用 Jackson 将嵌套数组反序列化为 ArrayList的主要内容,如果未能解决你的问题,请参考以下文章
使用 Jackson 和 Spring 将 JavaScript 数组反序列化为 Java LinkedHashSet 不会删除重复项
如何使用 Jackson 将原始 JSON 反序列化为 Java 对象