2015-01-12 26 views
17

Tôi có một mảnh JSON, trông như thế này:Deserialize mảng lồng nhau như ArrayList với Jackson

{ 
    "authors": { 
    "author": [ 
     { 
     "given-name": "Adrienne H.", 
     "surname": "Kovacs" 
     }, 
     { 
     "given-name": "Philip", 
     "surname": "Moons" 
     } 
    ] 
    } 
} 

Tôi đã tạo ra một lớp học để lưu trữ thông tin Tác giả:

public class Author { 
    @JsonProperty("given-name") 
    public String givenName; 
    public String surname; 
} 

Và hai lớp wrapper :

public class Authors { 
    public List<Author> author; 
} 

public class Response { 
    public Authors authors; 
} 

Điều này đang hoạt động nhưng có hai lớp trình bao bọc dường như không cần thiết. Tôi muốn tìm cách xóa lớp Authors và có danh sách là thuộc tính của lớp Nhập. Có chuyện như thế có thể xảy ra với Jackson không?

Cập nhật

Giải Quyết rằng với tùy chỉnh 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); 
    } 
} 

Và sử dụng nó như thế này:

@JsonDeserialize(using = AuthorArrayDeserializer.class) 
public void setAuthors(List<Author> authors) { 
    this.authors = authors; 
} 

Cảm ơn @wassgren cho ý tưởng.

+0

trả lời giúp bạn –

Trả lời

7

Tôi thấy ít nhất hai cách tiếp cận để thực hiện việc này nếu bạn muốn loại bỏ các lớp trình bao bọc. Đầu tiên là sử dụng mô hình cây Jackson (JsonNode) và thứ hai là sử dụng một tính năng deserialization gọi là UNWRAP_ROOT_VALUE.


Alternative 1: Sử dụng JsonNode

Khi deserializing JSON sử dụng Jackson có nhiều cách để kiểm soát những gì loại của các đối tượng đó sẽ được tạo ra. ObjectMapper có thể deserialize JSON, ví dụ: a Map, JsonNode (qua số readTree -method) hoặc POJO.

Nếu bạn kết hợp readTree -method với chuyển đổi POJO, trình bao bọc có thể được xóa hoàn toàn. Ví dụ:

// 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; 
    } 
} 

Các deserialization sau đó có thể trông giống như thế này:

// 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... 

Nếu bạn sử dụng cây này Model-tiếp cận các lớp wrapper có thể được loại bỏ hoàn toàn.


Phương án 2: loại bỏ một trong những giấy gói và unwrap giá trị gốc Cách tiếp cận thứ hai là để loại bỏ chỉ một trong những giấy gói. Giả sử rằng bạn loại bỏ lớp Authors nhưng giữ cho Response -wrapper. Nếu bạn thêm số @JsonRootName -annotation, sau đó bạn có thể bỏ qua tên cấp cao nhất.

@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; 
    } 
} 

Sau đó, cho mapper bạn chỉ cần sử dụng:

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); 

Cách tiếp cận thứ hai chỉ loại bỏ một trong các lớp wrapper nhưng thay vào đó là chức năng phân tích cú pháp là khá đẹp.

+0

cảm ơn, tôi sẽ thử phương pháp này. – Dmitry

Các vấn đề liên quan