簡體   English   中英

如何在Java中解析對象的JSON數組

[英]How to parse a JSON array of objects in Java

我從未嘗試過解析JSON。 我有一些像這樣的JSON格式的書:

{
"Search": {
    "Books": [
        {
            "isbn": "1849830347",
            "title": "American Assassin",
            "author": "Vince Flynn",
            "price": 7.99
        },
        {
            "isbn": "0857208683",
            "title": Kill Shot",
            "author": "Vince Flynn",
            "price": 5.99
        },
        ...
    }
}

我想要的是解析它們,並得到一個已填充Book對象的列表。 我曾與Jackson和Google的GSON一起玩過。 我終於讓它起作用了,但是我對此並不滿意。 這只是有效的代碼,我希望我的解決方案成為將來再次使用JSON時的良好代碼-我認為這是低效的,因為我先將其變成一棵樹然后對其進行解析。 誰能提出改進建議?

List<Book> books = new ArrayList<Book>();
JsonFactory f = new JsonFactory();
JsonParser jp = f.createJsonParser(json);
jp.setCodec(new ObjectMapper());
JsonNode node = jp.readValueAsTree();

JsonNode books = node.findValue("Books");

Iterator<JsonNode> it = books.getElements();
while(it.hasNext()){
    JsonNode temp = it.next();
    Book book = new Book();
    book.setIsbn(temp.findValue("isbn").asText());
    book.setTitle(temp.findValue("title").asText());
    book.setAuthor(temp.findValue("author").asText());
    book.setPrice(temp.findValue("price").asDouble());
    books.add(book);
}

我擁有setCodec行的唯一原因是因為沒有它,我得到了一條IllegalStateException消息:沒有為解析器定義ObjectObjectc,無法將JSON反序列化為JsonNode樹。

Jackson API開始 ,我嘗試使用Streaming API方法。 但是我不得不調用jp.nextToken()大約10次,以獲取第一個isbn值,而且看起來非常混亂。 盡管API確實說了20%/ 30%的速度。

感謝對此的任何反饋。

您可以在Gson中編寫自己的反序列化器: https : //sites.google.com/site/gson/gson-user-guide#TOC-Writing-a-Deserializer

或者,您可以使用所需的設置器創建一個Object,然后讓Gson進行: http : //java.dzone.com/articles/deserializing-json-java-object

一些可用的JSON庫或多或少都很麻煩。 我認為遍歷樹是使用外部庫時您不應該關心的事情之一。 在這種情況下,您甚至可以自己編寫。

但是我前段時間找到了一個不錯的庫json-io ,它可以為您完成所有這些工作。 該庫的缺點是它不能很好地與Android一起使用。 (我在Android上遇到了OutOfMemory異常。)

Jackson提供了三個“層次”的解析:流API是基礎層,並且在JSON之上將JSON解析為樹節點或您自己的類。 正如您所發現的,盡管直接使用流API可能是最有效的,但它需要大量的人工。

實際上,您所需的大部分內容似乎都在1分鍾的教程中 ,無需繼續學習!

無需解析到JsonNode,Jackson可以直接創建/填充您自己的Book對象。 由於您已經有bean風格的二傳手,這應該是一個簡單的插件。

(順便說一句,典型的用法是首先創建一個ObjectMapper(通常作為一個單例),然后從中創建JsonFactory,ObjectReader等,而不是反過來)

因此,您可以像這樣讀取一個Book對象:

Book book = mapper.readValue("{\"isbn\":\"1849830347\"}", Book.class);

您可以在“搜索”鍵下創建某種包裝對象來表示該對象:

/*static*/ class SearchResult {
    @JsonProperty("Books")
    public List<Book> books;
}
SearchResult result = mapper.readValue("{\"Books\":[{\"isbn\":\"...\"}]}", SearchResult.class);
List<Book> books = result.books;

@JsonProperty需要指定一個大寫的“ Books”字段名稱,而不是默認名稱。為簡便起見,顯示為公共字段,帶有getter和setter的私有字段也適用)

然后,您可以添加另一層對象來表示整個消息,或者添加一個@JsonRootName批注以告訴Jackson在SearchResult為“ root”類型時進行額外的解包級別:

@JsonRootName(value="Search")
class SearchResult { ... }

很多時候,您可以避免直接與Jackson一起使用JsonNode,JsonFactory等。 如果僅對屬性名稱等類進行注釋,那么您幾乎沒有其他要做的事情來對稱地使用這些類進行解析格式化。

我已經在許多項目中使用過Jackson,並且將來會毫不猶豫地再次使用它。

在大多數情況下,我喜歡開發為JSON消息建模的Java POJO。 因此,在您的情況下,您需要使用Book POJO來對JSON的此內部部分進行建模

{
     "isbn": "1849830347",
     "title": "American Assassin",
     "author": "Vince Flynn",
     "price": 7.99
 }

匹配的POJO就是這個

public class BookVO {

    private final String isbn;
    private final String title;
    private final String author;
    private final double price;

    @JsonCreator
    public BookVO(@JsonProperty("isbn") final String isbn, @JsonProperty("title") final String title, @JsonProperty("author") final String author, @JsonProperty("price") final double price) {
        super();
        this.isbn = isbn;
        this.title = title;
        this.author = author;
        this.price = price;
    }

    public String getIsbn() {
        return isbn;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public double getPrice() {
        return price;
    }

}

上面這本書的父母POJO是這個

public class BookSearchVO {

    private final BookVO[] books;

    @JsonCreator
    public BookSearchVO(@JsonProperty("Books") final BookVO[] books) {
        super();
        this.books = books;
    }

    public BookVO[] getBooks() {
        return books;
    }

}

祖父母POJO是這個

public class SearchVO {

    private final BookSearchVO search;

    @JsonCreator
    public SearchVO(@JsonProperty("Search") final BookSearchVO search) {
        super();
        this.search = search;
    }

    public BookSearchVO getSearch() {
        return search;
    }

}

只需將JSON轉換為Java對象

final ObjectMapper mapperBook = new ObjectMapper();
final SearchVO results = mapperBook.readValue(new File("books.json"), SearchVO.class);

books.json的內容是

{
   "Search":{
      "Books":[
         {
            "isbn":"1849830347",
            "title":"American Assassin",
            "author":"Vince Flynn",
            "price":7.99
         },
         {
            "isbn":"0857208683",
            "title":"Kill Shot",
            "author":"Vince Flynn",
            "price":5.99
         }
      ]
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM