如何在Java中解析JSON对象数组

时间:2015-05-30 15:55:40

标签: java json jackson

我之前从未尝试过解析JSON。我有一些像这样的JSON格式的书:

df_new = df.groupby('video_id').agg({"ios_id": np.count_nonzero,
                                     "ios_id": pd.Series.nunique,
                                     "feed_position": np.average,
                                     "time_watched": np.sum,
                                     "video_length": np.sum}).sort('ios_id', ascending=False)

我想要的是解析它们并最终得到一个已填充的Book对象列表。我和杰克逊以及谷歌的GSON一起玩过。我终于开始工作,但我并不满意。这只是有效的代码,我希望我的解决方案是将来再次使用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
        },
        ...
    }
}

我拥有setCodec行的唯一原因是因为没有它,我得到一个带有消息的IllegalStateException:没有为解析器定义的ObjectCodec,不能将JSON反序列化为JsonNode树。

Jackson API开始,我尝试使用Streaming API方法。但我不得不调用jp.nextToken()大约10次才能获得第一个isbn值,它看起来非常混乱。虽然API确实说它的速度提高了20%/ 30%。

感谢对此的任何反馈。

4 个答案:

答案 0 :(得分:2)

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

或者您可以使用所需的setter创建一个Object并让Gson完成工作: http://java.dzone.com/articles/deserializing-json-java-object

答案 1 :(得分:0)

一些可用的JSON库或多或少都很麻烦。在我看来,遍历树是使用外部库时不应该关心的事情之一。在这种情况下,您甚至可以自己编写。

但是我前面找到了一个很好的库,它可以帮助你完成所有这些工作,名为json-io。 这个库的缺点是它不能很好地与Android一起使用。 (我在Android上获得了OutOfMemory异常。)

答案 2 :(得分:0)

杰克逊提供三个级别"解析:流API是基础层,并且在此基础上提供了将JSON解析为树节点或您自己的类。虽然直接使用流式传输API可能效率最高,但正如您所发现的那样,需要大量人力。

事实上,你需要的大部分内容似乎都在1-minute tutorial中,无需向前跳!

Jackson可以直接创建/填充您自己的Book对象,而不是解析为JsonNode。由于你已经拥有了bean风格的setter,所以这应该是一个简单的插件。

(BTW的典型用法是最初创建一个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需要指定一个大写的&#34; Books&#34;字段名称,而不是默认值。为了简洁起见,显示为公共字段,带有getter和setter的私有字段也可以工作)< / p>

然后你可以添加另一层对象来表示整个消息,或添加一个@JsonRootName注释来告诉Jackson在SearchResult是&#34; root&#34;时进行额外的解包。类型:

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

很多时候你可以避免直接使用JsonNode,JsonFactory等杰克逊。如果你只注释属性名称等的类,那么你只需要对称地使用这些类来解析格式。

答案 3 :(得分:0)

我在很多项目中都使用过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;
    }

}

Grand Parent 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
         }
      ]
   }
}