繁体   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