2015-05-30 11 views
1

Я никогда не пытался разбирать JSON раньше. У меня есть несколько книг в формате JSON как это:Как разбирать массив объектов JSON в Java

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

То, что я хочу, чтобы разобрать их и в конечном итоге со списком заселенных объектов книги. Я играл с Джексоном и с GSON от Google. Я, наконец, получил это, но я не очень доволен этим. Это всего лишь код, который работает, и я хочу, чтобы мое решение было хорошим кодом, когда я снова работаю с 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 с сообщением: Нет ObjectCodec определен для синтаксического анализа, не может десериализации JSON в JsonNode дерево.

От Jackson API, я попытался использовать метод Streaming API. Но мне пришлось вызвать jp.nextToken() примерно в 10 раз, чтобы перейти к первому значению isbn, и это выглядело очень грязно. Хотя API говорит, что он на 20%/30% быстрее.

Оцените любые отзывы об этом.

+0

Возможный дубликат: http://stackoverflow.com/questions/6349421/how- to-use-jackson-to-deserialise-a-array-of-objects –

ответ

2

Вы можете написать свой собственный десериализатор в Gson: https://sites.google.com/site/gson/gson-user-guide#TOC-Writing-a-Deserializer

Или вы можете создать объект с необходимыми сеттеров и пусть Gson сделать работу: http://java.dzone.com/articles/deserializing-json-java-object

+0

по моему опыту, вы быстро достигаете DEAD END с помощью GSON. Похоже, что он решает простейшие проблемы JSON. – Hector

0

Некоторые библиотеки JSON, которые доступны более или менее громоздким. По-моему, обход дерева - одна из тех вещей, на которые вам не следует заботиться при использовании внешней библиотеки. В этом случае вы даже можете написать это самостоятельно.

Но есть одна хорошая библиотека, которую я нашел некоторое время назад, которая делает все это для вас, называется json-io. Недостатком этой библиотеки является то, что она не очень хорошо работает с Android. (Я получил исключения OutOfMemory на Android.)

0

Jackson предоставляет три «уровня» синтаксического анализа: потоковый API является базовым уровнем, а синтаксический анализ JSON на узлы дерева или ваши собственные классы предоставляются поверх этого. Хотя использование потокового API напрямую может быть наиболее эффективным, для этого требуется много труда, как вы нашли.

На самом деле большинство из того, что вам нужно, похоже, находится в 1-minute tutorial, не нужно прыгать вперед!

Вместо того, чтобы разыгрывать JsonNode, Джексон может создавать/заполнять ваши собственные объекты Book напрямую. Поскольку у вас уже есть компоновщики бин-стиля, это должно быть простым входом.

(BTW типичное использование состоит в создании ObjectMapper обычно initially-- как singleton-- и создать JsonFactory, ObjectReader и т.д. от него, а не наоборот)

Таким образом, вы могли бы прочитать один объект книги, как так:

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 необходимо указать имя поля в верхнем регистре «Книги», а не по умолчанию. В качестве публичного поля для краткости также используется частное поле с геттером и сеттером)

И тогда вы можете добавить еще один слой объекта для представления всего сообщения или добавить аннотацию @JsonRootName, чтобы сообщить Джексону сделать дополнительный уровень из разворачивания, когда SearchResult является «корнем» Тип:

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

много времени вы можете избежать использования JsonNode, JsonFactory и т.д. непосредственно с Джексоном. Если вы только аннотируете классы для имен свойств и т. Д., То вам нечего делать, чтобы использовать классы симметрично для разбора и форматирования.

0

Я использовал Джексон во многих проектах и ​​буду использовать его снова в будущем без колебаний.

В большинстве случаев мне нравится разрабатывать java POJO, которые моделируют сообщение JSON. так что в вашем случае вам потребуется книга 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 
     } 
     ] 
    } 
} 
Смежные вопросы