使用 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 反序列化为例如MapJsonNode(通过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 不会删除重复项

Json.NET:将嵌套数组反序列化为强类型对象

如何使用 Jackson 将原始 JSON 反序列化为 Java 对象

Jackson - 将内部对象列表反序列化为更高级别的列表

使用 Jackson XmlMapper 将 XML 反序列化为 POJO

Jackson 使用枚举键、POJO 值反序列化为 Map