Как парсить json на java
Перейти к содержимому

Как парсить json на java

  • автор:

Как и чем парсить Json на Java?

Часто возникает потребность работы с Json, в частности его чтения и парсинга. В Java обычно ты знаешь с каким типом переменных работаешь, а при парсинге Json смущает то, что тип полей может быть любой. Какие есть способы разбора Json? Как это делать? Вот, допустим, как достать данные из Json, представленного ниже?

< "firstName": "Json", "lastName": "Smith", "age": 30, "address": < "streetAddress": "666 1nd Street", "city": "New York", "state": "NY", "postalCode": 10021 >, "phoneNumbers": [ < "type": "home", "number": "542 666-1234" >, < "type": "fax", "number": "653 666-4567" >], "friends": [ < "firstName": "Test", "lastName": "Snow", "age": 20, "phoneNumbers": [ < "type": "home", "number": "141 111-1234" >], "friends": [ < "firstName": "UnknownFirstName", "lastName": "UnknownLastName", "age": 999, "phoneNumbers": [ < "type": "home", "number": "000 000-0000" >] > ] >, < "firstName": "Flash", "lastName": "Tompson", "age": 23, "phoneNumbers": [ < "type": "home", "number": "999 111-1234" >] > ] > 

Отслеживать
28.8k 12 12 золотых знаков 59 59 серебряных знаков 118 118 бронзовых знаков
задан 15 ноя 2017 в 13:35
Алексей Шиманский Алексей Шиманский
72.3k 12 12 золотых знаков 92 92 серебряных знака 180 180 бронзовых знаков

4 ответа 4

Сортировка: Сброс на вариант по умолчанию

Достать данные можно разными способами и, конечно, зависит от задач. Попробую рассмотреть некоторые варианты разбора Json.

Заметка: для каждого из примеров для парсинга будет взят Json из вопроса, чтобы зря не копировать в ответ.

Simple Json

Где взять: здесь / репозиторий на github / или через Maven и пр.

Это самый примитивный способ. По сути, всё, что тут есть — это JSONObject и JSONArray .

  • JSONArray может включать в себя несколько объектов JSONObject , его можно обходить циклом на каждой итерации получая объект JSONObject .
  • JSONObject — объект, из которого можно доставать его отдельные свойства.

Я бы использовал его для небольших Json строк, где не надо сильно заморачиваться или если не лень писать свой класс-обработчик на основе кода, который продемонстрирован ниже:

// Считываем json Object obj = new JSONParser().parse(jsonString); // Object obj = new JSONParser().parse(new FileReader("JSONExample.json")); // Кастим obj в JSONObject JSONObject jo = (JSONObject) obj; // Достаём firstName and lastName String firstName = (String) jo.get("firstName"); String lastName = (String) jo.get("lastName"); System.out.println("fio: " + firstName + " " + lastName); // Достаем массив номеров JSONArray phoneNumbersArr = (JSONArray) jo.get("phoneNumbers"); Iterator phonesItr = phoneNumbersArr.iterator(); System.out.println("phoneNumbers:"); // Выводим в цикле данные массива while (phonesItr.hasNext())

Остальная работа с вложенными массивами аналогична. Можно складывать в List, Map и пр.

GSON

Где взять: здесь / репозиторий на github / или через Maven и пр.

Позволяет парсить Json также, как и Json-simple, т.е. используя JSONObject и JSONArray (см. документацию), но имеет более мощный инструмент парсинга. Достаточно создать классы, которые повторяют структуру Json‘а. Для парсинга Json из вопроса создадим классы:

class Person < public String firstName; public String lastName; public int age; public Address address; public ListphoneNumbers; public List friends; > class Address < public String streetAddress; public String city; public String state; public int postalCode; >class Phones

Теперь достаточно написать:

Gson g = new Gson(); Person person = g.fromJson(jsonString, Person.class); 

Всё! Магия! Чудо! Теперь в person лежит объект с типом Person , в котором находятся данные именно с теми типами, которые были указаны в созданных классах! Теперь можно работать с любым типом, как это привыкли всегда делать: String, Integer, List, Map и всё остальное.

// Выведет фамилии всех друзей с их телефонами for (Person friend : person.friends) < System.out.print(friend.lastName); for (Phones phone : friend.phoneNumbers) < System.out.println(" - phone type: " + phone.type + ", phone number : " + phone.number); >> // output: // Snow - phone type: home, phone number : 141 111-1234 // Tompson - phone type: home, phone number : 999 111-1234 

Пример парсинга в Map :

. JSON для разбора:

< "2":< "sessions":[ < "time":"13:00", "price":"410" >, < "time":"06:40", "price":"340" >, < "time":"16:50", "price":"370" >], "name":"Кинокис-L", "locate":"Москва, Садовая-Спасская ул., 21, 56", "metro":"Красные ворота" >, "7":< "sessions":[ < "time":"06:35", "price":"190" >, < "time":"00:05", "price":"410" >], "name":"Кинокис-V", "locate":"Павелецкая пл., 2, строение 1", "metro":"Павелецкая" >, "8": < "sessions":[ < "time":"15:10", "price":"330" >], "name":"Кинокис-J", "locate":"ул. Пречистенка, 40/2", "metro":"Кропоткинская" >, "9":< "sessions":[ < "time":"13:00", "price":"600" >, < "time":"08:30", "price":"300" >, < "time":"04:00", "price":"510" >, < "time":"13:15", "price":"340" >], "name":"Кинокис-U", "locate":"Шарикоподшипниковская ул., 24", "metro":"Дубровка" > >
class Seanse < public String name; public String locate public String metro; public Listsessions; > class Sessions

. Сам разбор выглядит так:

Gson g = new Gson(); Type type = new TypeToken>()<>.getType(); Map myMap = g.fromJson(json, type); 

Дополнительно в GSON можно использовать аннотации, например: исключить указанные поля при парсинге, поменять имя переменной (например не personFirstName , а fName ) и многое другое. Подробнее см. в документации.

Jackson

Где взять: здесь / репозиторий на github / или через Maven и пр.

Как и GSON он также позволяет работать используя JSONObject и JSONArray если это требуется, и тоже умеет парсить на основе предоставленных классов (см. пример ниже).

Аналогично в нем можно указывать дополнительные требования за счет аннотаций, например: не парсить указанные поля, использовать кастомный конструктор класса, поменять имя переменной (например не firstName , а fName ) и многое другое. Подробнее см. в документации.

ObjectMapper mapper = new ObjectMapper(); Person person = mapper.readValue(jsonString, Person.class); System.out.println("My fio: " + person.firstName + " " + person.lastName + " and my friends are: "); for (Person friend : person.friends) < System.out.print(friend.lastName); for (Phones phone : friend.phoneNumbers) < System.out.println(" - phone type: " + phone.type + ", phone number : " + phone.number); >> // output: // My fio: Json Smith and my friends are: // Snow - phone type: home, phone number : 141 111-1234 // Tompson - phone type: home, phone number : 999 111-1234 

JsonPath

Где взять: через Maven и другие сборщики / репозиторий на github

Относится к так называемым XPath библиотекам. Её суть аналогична xpath в xml, то есть легко получать часть информации из json‘а, по указанному пути. А также позволяет фильтровать по условию.

// Выведет все фамилии друзей List friendsLastnames = JsonPath.read(jsonString, "$.friends[*].lastName"); for (String lastname : friendsLastnames) < System.out.println(lastname); >// output: // Snow // Tompson 

Пример с выборкой по условию:

// Поиск друга, которому больше 22 лет List friendsWithAges = JsonPath .using(Configuration.defaultConfiguration()) .parse(jsonString) .read("$.friends[?(@.age > 22)].lastName", List.class); for (String lastname : friendsWithAges) < System.out.println(lastname); >// output: // Tompson 

Отслеживать
ответ дан 15 ноя 2017 в 13:35
Алексей Шиманский Алексей Шиманский
72.3k 12 12 золотых знаков 92 92 серебряных знака 180 180 бронзовых знаков
У GSON также наличествует возможность менять поведение аннотациями
15 ноя 2017 в 14:08

Понимаю, зачем ТС задал такой вопрос и сам же на него и ответил, ибо действительно достали вопросы новичков как парсить Json. Предлагаю ответ сделать общим и на вопросы по Json далее ставить дубли со ссылкой на этот ответ.

15 ноя 2017 в 14:23

@Barmaley я бы предложил писать еще ответы, чтоб хотя бы ответ не был полотном гигантским. И еще хочу ЮрийСПб попросить чтоб отдельно написал ответы по Android, думаю там есть что-то тоже отдельно

15 ноя 2017 в 14:31
@rjhdby добавил сий нюанс в ответ.
15 ноя 2017 в 15:27
@Barmaley, для этого не надо ничего делать общим.
20 ноя 2017 в 18:56

Еще несколько вариантов

LoganSquare

LoganSquare — основана на Jackson‘s streaming API. По демонстрируемым тестам работает быстрее GSON и Jackson. Поэтому хорош для Android.

Где взять: репозиторий на github / или через Maven / Gradle и пр.

  • Классы должны быть помечены аннотацией @JsonObject
  • Поля должны быть помечены аннотацией @JsonField (с различными варианциями входных параметров, например @JsonField(name=»message») )
  • Другие предъявляемые требования: https://github.com/bluelinelabs/LoganSquare/blob/development/docs/Models.md
@JsonObject public class Person < @JsonField(name="firstName") public String firstName; @JsonField(name="age") public int age; public void say() < System.out.println(); System.out.println("My name is " + firstName + " , I'm " + age + " years old!"); >> 
String jsonString = ""; Person person = LoganSquare.parse(jsonString, Person.class); person.say(); // My name is Adam , I'm 18 years old! 

Moshi

Moshi is a modern JSON library for Android and Java.

Хорош, как утверждают разработчики, для работы с Android.

Где взять: репозиторий на github / или через Maven / Gradle и пр.

    Пример разбора Json строки в объект Person :

Moshi moshi = new Moshi.Builder().build(); JsonAdapter jsonAdapter = moshi.adapter(Person.class); Person person = jsonAdapter.fromJson(jsonStringPerson); // В person будут все данные 
class Seanse < public String name; public String locate public String metro; public Listsessions; > class Sessions < public String time; public double price; >public class Main < public static void main(String[] args) throws IOException < String jsonStringForMap = "<\"2\":<\"sessions\":[<\"time\":\"13:00\",\"price\":\"410\">,< \"time\":\"06:40\",\"price\":\"340\">,< \"time\":\"16:50\",\"price\":\"370\">],\"name\":\"Кинокис-L\",\"locate\":\"Москва, Садовая-Спасская ул., 21, 56\",\"metro\":\"Красные ворота\">,\"7\":< \"sessions\":[ < \"time\":\"06:35\",\"price\":\"190\">,< \"time\":\"00:05\",\"price\":\"410\">],\"name\":\"Кинокис-V\",\"locate\":\"Павелецкая пл., 2, строение 1\",\"metro\":\"Павелецкая\">,\"8\":< \"sessions\":[ < \"time\":\"15:10\",\"price\":\"330\">],\"name\":\"Кинокис-J\",\"locate\":\"ул. Пречистенка, 40/2\",\"metro\":\"Кропоткинская\">,\"9\":< \"sessions\":[ < \"time\":\"13:00\",\"price\":\"600\">,< \"time\":\"08:30\",\"price\":\"300\">,< \"time\":\"04:00\",\"price\":\"510\">,< \"time\":\"13:15\",\"price\":\"340\">],\"name\":\"Кинокис-U\",\"locate\":\"Шарикоподшипниковская ул., 24\",\"metro\":\"Дубровка\">>"; Moshi moshi = new Moshi.Builder().build(); Type map = Types.newParameterizedType(Map.class, String.class, Seanse.class); JsonAdapter> jsonAdapter = moshi.adapter(map); Map seanseMap = jsonAdapter.fromJson(jsonStringForMap); > > 

Genson

Где взять: здесь / репозиторий на github / или через Maven и пр.

За счет создания POJO (создаются классы, которые повторяют структуру Json‘а) — парсится объект из строки, распихивая по нужным полям объектов. Есть возможность фильтровать свойства, включить или исключить поля при парсинге, переименовать, возможность работы с аннотациями и пр. Подробнее в документации.

Genson genson = new Genson(); Person person = genson.deserialize(jsonString, Person.class); // В person будут все данные 
List persons = genson.deserialize("[, ]", List.class); // persons - список с данными объектов 

. JSON для разбора:

< "2":< "sessions":[ < "time":"13:00", "price":"410" >, < "time":"06:40", "price":"340" >, < "time":"16:50", "price":"370" >], "name":"Кинокис-L", "locate":"Москва, Садовая-Спасская ул., 21, 56", "metro":"Красные ворота" >, "7":< "sessions":[ < "time":"06:35", "price":"190" >, < "time":"00:05", "price":"410" >], "name":"Кинокис-V", "locate":"Павелецкая пл., 2, строение 1", "metro":"Павелецкая" >, "8": < "sessions":[ < "time":"15:10", "price":"330" >], "name":"Кинокис-J", "locate":"ул. Пречистенка, 40/2", "metro":"Кропоткинская" >, "9":< "sessions":[ < "time":"13:00", "price":"600" >, < "time":"08:30", "price":"300" >, < "time":"04:00", "price":"510" >, < "time":"13:15", "price":"340" >], "name":"Кинокис-U", "locate":"Шарикоподшипниковская ул., 24", "metro":"Дубровка" > >
class Seanse < public String name; public String locate public String metro; public Listsessions; > class Sessions
String jsonStringForMap = "ТУТ JSON СТРОКА, ОПИСАННАЯ ВЫШЕ"; Genson genson = new Genson(); Map seansesMap = genson.deserialize(jsonStringForMap, Map.class); 

FastJson

Где взять: через Maven и другие сборщики / репозиторий на github. Непосредственно описание работы с xpath. Осторожно, ̶н̶е̶н̶о̶р̶м̶а̶т̶и̶в̶н̶а̶я̶ ̶л̶е̶к̶с̶и̶к̶а̶ китайский язык.

Относится к XPath аналогам.

Person person = JSON.parseObject(jsonString, Person.class); int age = person.age; System.out.println(age); // 30 
// Выведет все фамилии друзей List friendsLastnames = (List) JSONPath.eval(person, "$.friends.lastName"); for (String lastname : friendsLastnames) < System.out.println(lastname); // Snow Tompson >// Поиск друга, которому больше 22 лет List friendsWithAges = (List) JSONPath.eval(person, "$.friends[?(@.age > 22)].lastName"); for (String lastname : friendsWithAges) < System.out.println(lastname); // Tompson >

Отслеживать
ответ дан 25 дек 2017 в 15:53
Алексей Шиманский Алексей Шиманский
72.3k 12 12 золотых знаков 92 92 серебряных знака 180 180 бронзовых знаков

JSON-P

Поддерживает сериализацию и парсинг JSON без предварительного маппинга в классах:

Maven:

 javax.json javax.json-api 1.1.2  org.glassfish javax.json 1.1.2  

Пример разбора строки JSON:

public static void main(String[] args) throws IOException

Пример вывода объекта в строку JSON:

public static void main(String[] args) throws IOException < System.out.println(prettyPrintJson(jsonObject, 0)); >public static String prettyPrintJson(JsonObject jsonObject, int indent) < String indentStr = getIndentStr(indent); String prettyJson = indentStr + "prettyJson = prettyJson.substring(0, prettyJson.length() - 1); prettyJson += "\n" + indentStr + " ]"; > catch (Exception e) < try < prettyJson += "\n" + prettyPrintJson(jsonObject.get(key).asJsonObject(), indent + 2); >catch (Exception ee) < prettyJson += jsonObject.get(key).toString(); >> prettyJson += ","; > prettyJson = prettyJson.substring(0, prettyJson.length() - 1); prettyJson += "\n" + indentStr + ">"; return prettyJson; > public static String getIndentStr(int indent) < String indentStr = ""; for (int i = 0; i < indent; i++) < indentStr += " "; >return indentStr; > 
< "firstName": "Json", "lastName": "Smith", "age": 30, "address": < "streetAddress": "666 1nd Street", "city": "New York", "state": "NY", "postalCode": 10021 >, "phoneNumbers": [ < "type": "home", "number": "542 666-1234" >, < "type": "fax", "number": "653 666-4567" >], "friends": [ < "firstName": "Test", "lastName": "Snow", "age": 20, "phoneNumbers": [ < "type": "home", "number": "141 111-1234" >], "friends": [ < "firstName": "UnknownFirstName", "lastName": "UnknownLastName", "age": 999, "phoneNumbers": [ < "type": "home", "number": "000 000-0000" >] > ] >, < "firstName": "Flash", "lastName": "Tompson", "age": 23, "phoneNumbers": [ < "type": "home", "number": "999 111-1234" >] > ] > 

Отслеживать
ответ дан 30 ноя 2017 в 15:43
user236980 user236980

Поддерживает сериализацию и парсинг JSON без предварительного маппинга в классах — потому что это ручной разбор, при котором разработчику известна структура и нужно писать велосипеды аналогично похожему Simple Json %)

30 ноя 2017 в 16:15

Когда известна структура наверно можно посмотреть ещё один sjr specification номер 367 или json-b (json binding)

26 дек 2017 в 13:30

Здесь расположена общая информация о парсерах, которая может помочь при выборе и понять, что он умеет. Текст и таблица, представленные ниже, взяты из публикации на Habrahabr: Шпаргалка Java программиста 8. Библиотеки для работы с Json, автор статьи @ВеденинВячеслав

  1. Data bind
  2. Tree Model
  3. Streaming API
  4. Аналоги XPath (дополнительный способ)

Data bind

Самый популярный и простой способ — вы просто указываете класс, который нужно преобразовать в json, может быть часть полей отмечаете аннотациями (а зачастую даже это необязательно), а библиотека сама превращает этот класс и всю его иерархию классов в json.

Плюсы: наиболее простой из всех

Минусы: скорость и память. Большинство библиотек использует рефлексию и т.п. методы работы с Java классами (хотя не все), что очевидно не очень быстро. К тому же, весь json файл сразу превращается в Java объекты, что может просто исчерпать всю доступную память, если вы попытаетесь обработать очень большой json.

Вывод: если нет проблем с производительностью, памятью и вы не собираетесь обрабатывать многогигабайтные json’ы скорее всего самый лучший способ.

Tree Model

Данный парсер представляет json в виде Java классов таких как Node или `JsonElement c иерархической структурой, а уже сам программист их обходит и получает из них информацию.

Плюсы: обычно быстрее первого способа и проще третьего

Минусы: уступает Data bind по простоте, плюс ряд библиотек способен генерить классы при Data bind, а не использовать рефлексию, в этом случае то что Tree Model будет быстрее не очевидно, к тому же не решается проблема огромных файлов и ограничения памяти.

Streaming API

Самый низкоуровневый способ, по сути программист сам вручную разбирает токены json’a. Зато никаких ограничений по памяти и в теории максимальная производительность.

Плюсы: производительность и минимальное потребление памяти

Минусы: сложность использования

Аналоги XPath

Не очень подходит, если нужно получит всю информацию из json‘a, зато позволяет написав выражение, например $.store.book[*].author получить список всех авторов всех книг из json‘a магазина. То есть легко получать часть информации из json‘а.

Плюсы: позволяет быстро получить информацию из json‘а по сложным критериям

Минусы: не очень подходит, когда нужна все информация из json‘а, не работает в обратную сторону на формирования json‘ов

Таблица библиотек и способы парсинга, которые они поддерживают:

Способ\Hазвание Fastjson Gson LoganSquare JSONjava Moshi Jackson Genson JsonPath SimpleJson Data bind Да Да Да - Да Да Да - - Tree Model - Да - Да - Да - - Да Streaming API - Да - - - Да - - - Аналоги XPath Да - - - - - - Да - Генерация классов - - Да - - - - - для Data bind* Работает со Да Да Нет - Да Да Да - static inner class** Обязательность Нет Нет Да - Нет Нет Нет - аннотаций*** 

* — Генерация классов для Data bind позволяет сгенерировать классы на стадии компиляции, что в теории должно давать значительный прирост производительности библиотеки,

** — Работает со static inner class имеет смысл только для случая Data bind, возможно ли сериализация и десериализация для случая статических внутренних классов (не статические внутренние классы сериализовать не рекомендуется),

*** — тоже только для случая Data bind можно ли не использовать аннотации или их использование крайне рекомендуется,

Java json parser – пример работы парсера

В этом посте мы разберем подробный пример парсера Java JSON. JSON(JavaScript Object Notation) – это простой текстовый формат, который облегчает чтение и запись. Это широко используемый формат обмена данными, поскольку его анализ и генерация просты в использовании.

В языке Java есть несколько способов обработки JSON. В этом примере мы собираемся использовать общий набор инструментов – JSON.simple – и узнаем, как анализировать каждый тип файла.

jsonobject

Установка среды

Перед началом написания кода программы, мы должны установить подходящую среду для компилятора, чтобы распознавать классы JSON. Если необходимо построить проект с помощью Maven, нужно добавить следующую запись в pom.xml:

 com.googlecode.json-simple json-simple 1.1  

Иначе необходимо добавить версию json-simple-1.1.1.jar в CLASSPATH.

Пример парсинга JSON

Разберем, как мы можем проанализировать и произвести чтение файла json, для этого нужно создать наш собственный файл, он будет называться jsonTestFile.json. Он имеет следующую структуру:

jsonTestFile.json: < "id": 1, "firstname": "Katerina", "languages": [ < "lang": "en", "knowledge": "proficient" >, < "lang": "fr", "knowledge": "advanced" >], "job": < "site": "www.hr-vector.com", "name": "Java Code" >>

Теперь необходимо создать файл Java в проекте с именем JsonParseTest и вставить следующий код.

package com.hrvector.javabasics.jsonparsertest; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.Iterator; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; public class JsonParseTest < private static final String filePath = "C:\\Users\\katerina\\Desktop\\jsonTestFile.json"; public static void main(String[] args) < try < // считывание файла JSON FileReader reader = new FileReader(filePath); JSONParser jsonParser = new JSONParser(); JSONObject jsonObject = (JSONObject) jsonParser.parse(reader); // получение строки из объекта String firstName = (String) jsonObject.get("firstname"); System.out.println("The first name is: " + firstName); // получение номера из объекта long jsonObject.get("id"); System.out.println("The id is: " + id); // получение массива JSONArray lang= (JSONArray) jsonObject.get("languages"); // берем элементы массива for(int i=0; iIterator i = lang.iterator(); // берем каждое значение из массива json отдельно while (i.hasNext()) < JSONObject innerObj = (JSONObject) i.next(); System.out.println("language "+ innerObj.get("lang") + " with level " + innerObj.get("knowledge")); >// обрабатываем структуру в объекте JSONObject structure = (JSONObject) jsonObject.get("job"); System.out.println("Into job structure, name: " + structure.get("name")); > catch (FileNotFoundException ex) < ex.printStackTrace(); >catch (IOException ex) < ex.printStackTrace(); >catch (ParseException ex) < ex.printStackTrace(); >catch (NullPointerException ex) < ex.printStackTrace(); >> >

Объясним данный код. После создания экземпляра JSONParser мы создаем объект JSONObject.

Он содержит коллекцию пар ключ-значение, из которых мы можем получить каждое значение. Чтобы распарсить объекты, вызывается метод get() экземпляра JSONObject, определяющий указанный ключ в качестве аргумента.

Важно применить подходящий метод. Для типов массивов в файле json используется JSONArray, который представляет упорядоченную последовательность значений. В программном коде итератор должен использоваться для получения каждого значения массива json.

Структура в файле предполагает создание нового объекта JSONObject для получения значений.

Полученный результат парсинга приведен ниже.

Output: The first name is: Katerina The id is: 1 The 0 element of the array: The 1 element of the array: language en with level proficient language fr with level advanced Into job structure, name: Java Code

Метод с использованием JsonPATH

Два приведенных выше примера требуют полной десериализации JSON в объект Java перед получением значения. Другой альтернативой является использование JsonPATH, который похож на XPath для JSON и позволяет обходить объекты JSON.

Вам нужно добавить JsonPATH, которую можно получить из репозитория maven.(https://mvnrepository.com/artifact/com.jayway.jsonpath/json-path)

import com.jayway.jsonpath.JsonPath; public class ParseJSON < static String json = ". "; public static void main(String[] args) < String pageName = JsonPath.read(json, "$.pageInfo.pageName"); System.out.println(pageName); Integer posts = JsonPath.read(json, "$.posts.length()"); for(int i=0; i < posts; i++) < String post_id = JsonPath.read(json, "$.posts[" + i + "].post_id"); System.out.println(post_id); >> >

java json parser пример

Средняя оценка 3.3 / 5. Количество голосов: 21

Спасибо, помогите другим — напишите комментарий, добавьте информации к статье.

Или поделись статьей

Видим, что вы не нашли ответ на свой вопрос.

Помогите улучшить статью.

Напишите комментарий, что можно добавить к статье, какой информации не хватает.

Парсинг JSON с помощью Jackson

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

Эта статья сопровождается примером рабочего кода на GitHub.

Что такое JSON?

JSON (от англ JavaScript Object Notation) — это текстовый формат для представления структурированных данных на основе синтаксиса объектов JavaScript. Благодаря своему гибкому и простому формату он стал чрезвычайно популярным. По сути, он следует модели карты «ключ-значение», допускающей вложенные объекты и массивы:

< "array": [ 1, 2, 3 ], "boolean": true, "color": "gold", "null": null, "number": 123, "object": < "a": "b", "c": "d" >, "string": "Hello World" >

Что такое Jackson?

Jackson в основном известен как библиотека, которая конвертирует строки JSON и простые объекты Java (англ POJO — Plain Old Java Object). Он также поддерживает многие другие форматы данных, такие как CSV, YML и XML.

Многие предпочитают Jackson благодаря его зрелости (он существует уже 13 лет) и отличной интеграции с популярными фреймворками, такими как Spring. Более того, это проект с открытым исходным кодом, который активно развивается и поддерживается широким сообществом.

Под капотом у Jackson есть три основных пакета: Streaming, Databind и Annotations. При этом Jackson предлагает нам три способа обработки преобразования JSON-POJO:

Потоковое API

Это самый быстрый подход из трех и с наименьшими накладными расходами. Он читает и записывает содержимое JSON в виде дискретных событий. API предоставляет JsonParser, который считывает JSON в POJO, и JsonGenerator, который записывает POJO в JSON.

Модель дерева

Модель дерева создает в памяти древовидное представление документа JSON. ObjectMapper отвечает за построение дерева из узлов JsonNode. Это наиболее гибкий подход, поскольку он позволяет перемещаться по дереву узлов, когда документ JSON не соответствует в достаточной мере POJO.

Привязка данных

Это позволяет нам выполнять преобразование между документами POJO и JSON с помощью средств доступа к свойствам или с помощью аннотаций. Он предлагает два типа привязки:

  • Простая привязка данных, которая преобразует JSON в Java Maps, Lists, Strings, Numbers, Booleans, null объекты и обратно.
  • Полная привязка данных, которая преобразует JSON в любой класс Java и из него.

ObjectMapper

ObjectMapper — наиболее часто используемая часть библиотеки Jackson, так как является самым простым способом преобразования между POJO и JSON. Она находится в com.fasterxml.jackson.databind .

Метод readValue() используется для преобразования (десериализации) JSON из строки, потока или файла в POJO.

С другой стороны, метод writeValue() используется для преобразования POJO в JSON (сериализация).

Способ, которым ObjectMapper определяет, какое поле JSON соответствует какому полю POJO, заключается в сопоставлении имен полей JSON с именами геттеров и сеттеров в POJO.

Это делается путем удаления частей «get» и «set» в именах геттеров и сеттеров и преобразования первого символа имени оставшегося метода в нижний регистр.

Например, предположим, у нас есть поле JSON с именем name : ObjectMapper сопоставит его с геттером getName() и сеттером setName() в POJO.

ObjectMapper является настраиваемым, и мы можем кастомизировать его в соответствии с нашими потребностями либо непосредственно через экземпляр ObjectMapper , либо с помощью аннотаций Jackson, как мы увидим позже.

Зависимости Maven

Прежде чем мы посмотрим на код, нам нужно добавить зависимость Jackson Maven jackson-databind, которая, в свою очередь, транзитивно добавляет jackson-annotations и jackson-core .

 com.fasterxml.jackson.core jackson-databind 2.13.3 

Мы также используем Lombok для обработки шаблонного кода для геттеров, сеттеров и конструкторов.

Базовая сериализация и десериализация JSON с Jackson

Давайте рассмотрим наиболее важные варианты использования Jackson с примерами кода.

Базовое преобразование POJO/JSON с использованием ObjectMapper

Давайте начнем с представления простого POJO под названием Employee:

@Getter @AllArgsConstructor @NoArgsConstructor public class Employee

Начнем с преобразования POJO в строку JSON:

public class JacksonTest < ObjectMapper objectMapper = new ObjectMapper(); @Test void pojoToJsonString() throws JsonProcessingException < Employee employee = new Employee("Mark", "James", 20); String json = objectMapper.writeValueAsString(employee); System.out.println(json); >>

В качестве вывода увидим следующее:

Теперь посмотрим, как преобразовать строку JSON в объект Employee с помощью ObjectMapper .

public class JacksonTest < . @Test void jsonStringToPojo() throws JsonProcessingException < String employeeJson = ""; Employee employee = objectMapper.readValue(employeeJson, Employee.class); assertThat(employee.getFirstName()).isEqualTo("Jalil"); > >

ObjectMapper также предлагает богатый API для чтения JSON из разных источников в разные форматы, давайте проверим самые важные из них.

Создание POJO из файла JSON

Это делается с помощью метода readValue() .

Файл JSON в тестовых ресурсах employee.json :

public class JacksonTest < . @Test void jsonFileToPojo() throws IOException < File file = new File("src/test/resources/employee.json"); Employee employee = objectMapper.readValue(file, Employee.class); assertThat(employee.getAge()).isEqualTo(44); assertThat(employee.getLastName()).isEqualTo("Simpson"); assertThat(employee.getFirstName()).isEqualTo("Homer"); >>
Создание POJO из массива байт в формате JSON
public class JacksonTest < . @Test void byteArrayToPojo() throws IOException < String employeeJson = ""; Employee employee = objectMapper.readValue(employeeJson.getBytes(), Employee.class); assertThat(employee.getFirstName()).isEqualTo("Jalil"); > >
Создание списка POJO из JSON

Иногда документ JSON представляет собой не объект, а список объектов. Давайте посмотрим, как можно его прочитать.

public class JacksonTest < . @Test void fileToListOfPojos() throws IOException < File file = new File("src/test/resources/employeeList.json"); ListemployeeList = objectMapper.readValue(file, new TypeReference<>()<>); assertThat(employeeList).hasSize(2); assertThat(employeeList.get(0).getAge()).isEqualTo(33); assertThat(employeeList.get(0).getLastName()).isEqualTo("Simpson"); assertThat(employeeList.get(0).getFirstName()).isEqualTo("Marge"); > >
Создание Map из JSON

Мы можем преобразовать JSON в Java Map , что очень удобно, если мы не знаем, чего ожидать от файла JSON, который мы пытаемся спарсить. ObjectMapper превратит имя каждой переменной в JSON в ключ для Map, а значение этой переменной — в значение по этому ключу.

public class JacksonTest < . @Test void fileToMap() throws IOException < File file = new File("src/test/resources/employee.json"); Mapemployee = objectMapper.readValue(file, new TypeReference<>()<>); assertThat(employee.keySet()).containsExactly("firstName", "lastName", "age"); assertThat(employee.get("firstName")).isEqualTo("Homer"); assertThat(employee.get("lastName")).isEqualTo("Simpson"); assertThat(employee.get("age")).isEqualTo(44); > >
Игнорирование неизвестных полей JSON

Иногда ожидаемый нами JSON может иметь дополнительные поля, не определенные в POJO. Поведение Jackson по умолчанию заключается в том, чтобы в таких случаях генерировать исключение UnrecognizedPropertyException . Однако же мы можем настроить Jackson так, чтобы он не расстраивался по поводу неизвестных полей и просто игнорировал их. Это делается путем установки FAIL_ON_UNKNOWN_PROPERTIES ObjectMapper в false.

public class JacksonTest < . @Test void fileToPojoWithUnknownProperties() throws IOException < File file = new File("src/test/resources/employeeWithUnknownProperties.json"); objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); Employee employee = objectMapper.readValue(file, Employee.class); assertThat(employee.getFirstName()).isEqualTo("Homer"); assertThat(employee.getLastName()).isEqualTo("Simpson"); assertThat(employee.getAge()).isEqualTo(44); >>

Работа с датами in Jackson

Преобразование дат может быть непростым занятием, поскольку они могут быть представлены во многих форматах и уровнях спецификации (секунды, миллисекунды и т. д.).

Дата в JSON

Прежде чем говорить о преобразовании дат и Jackson, нам нужно поговорить о новом Date API в Java 8. Он был введен для устранения недостатков более старых java.util.Date и java.util.Calendar . В основном нас интересует использование класса LocalDate , который предлагает эффективный способ представления даты и времени.

Для этого нам нужно добавить в Jackson дополнительный модуль, чтобы он мог обрабатывать LocalDate .

 com.fasterxml.jackson.datatype jackson-datatype-jsr310 2.13.3 

Затем нам нужно сказать ObjectMapper найти и зарегистрировать новый модуль, который мы только что добавили.

public class JacksonTest < ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules(); . @Test void orderToJson() throws JsonProcessingException < Order order = new Order(1, LocalDate.of(1900,2,1)); String json = objectMapper.writeValueAsString(order); System.out.println(json); >>

В этом случае поведение Jackson по умолчанию состоит в том, чтобы показывать дату как [гггг-ММ-дд]. Таким образом, вывод будет

Однако мы можем указать Jackson, в каком формате нам нужна дата. Это можно сделать с помощью аннотации @JsonFormat .

public class Order < private int id; @JsonFormat(pattern = "dd/MM/yyyy") private LocalDate date; >
@Test void orderToJsonWithDate() throws JsonProcessingException
JSON в дату

Мы можем использовать ту же конфигурацию выше, чтобы преобразовать поле JSON в дату.

public class JacksonTest < . @Test void fileToOrder() throws IOException < File file = new File("src/test/resources/order.json"); Order order = objectMapper.readValue(file, Order.class); assertThat(order.getDate().getYear()).isEqualTo(2000); assertThat(order.getDate().getMonthValue()).isEqualTo(4); assertThat(order.getDate().getDayOfMonth()).isEqualTo(30); >>

Аннотации Jackson

Важную роль в настройке процесса преобразования JSON/POJO играют аннотации. Мы видели пример с преобразованием даты, где мы использовали аннотацию @JsonFormat . Аннотации влияют на то, как данные читаются, записываются или даже на то и другое. Давайте рассмотрим некоторые из этих аннотаций на основе их категорий.

Аннотации чтения

Они влияют на то, как Jackson преобразует JSON в POJO.

@JsonSetter

Это полезно, когда мы хотим сопоставить поле в строке JSON с полем в POJO, где их имена не совпадают.

@NoArgsConstructor @AllArgsConstructor @Getter public class Car
public class JacksonTest < . @Test void fileToCar() throws IOException < File file = new File("src/test/resources/car.json"); Car car = objectMapper.readValue(file, Car.class); assertThat(car.getBrand()).isEqualTo("BMW"); >>

@JsonAnySetter

Эта аннотация полезна в случаях, когда JSON содержит некоторые поля, не объявленные в POJO. Он используется с сеттером, который вызывается для каждого нераспознанного поля.

public class Car < @JsonSetter("carBrand") private String brand; private MapunrecognizedFields = new HashMap<>(); @JsonAnySetter public void allSetter(String fieldName, String fieldValue) < unrecognizedFields.put(fieldName, fieldValue); >>
public class JacksonTest < . @Test void fileToUnrecognizedCar() throws IOException < File file = new File("src/test/resources/carUnrecognized.json"); Car car = objectMapper.readValue(file, Car.class); assertThat(car.getUnrecognizedFields()).containsKey("productionYear"); >>
Аннотации записи

Они влияют на то, как Jackson преобразует POJO в JSON.

@JsonGetter

Это полезно, когда мы хотим сопоставить поле POJO с полем JSON, используя другое имя. Например, предположим, что у нас есть класс Cat с полем name , но мы хотим, чтобы его JSON-имя было catName .

@NoArgsConstructor @AllArgsConstructor public class Cat < private String name; @JsonGetter("catName") public String getName() < return name; >>
public class JacksonTest < . @Test void catToJson() throws JsonProcessingException < Cat cat = new Cat("Monica"); String json = objectMapper.writeValueAsString(cat); System.out.println(json); >>

@JsonAnyGetter

Эта аннотация позволяет нам использовать объект Map как источник свойств JSON. Скажем, у нас есть эта карта как поле в классе Cat .

@NoArgsConstructor @AllArgsConstructor public class Cat < private String name; @JsonAnyGetter Mapmap = Map.of( "name", "Jack", "surname", "wolfskin" ); . >
@Test void catToJsonWithMap() throws JsonProcessingException

Вывод будет следующим:

Аннотации чтения и записи

Эти аннотации влияют как на чтение, так и на запись JSON.

@JsonIgnore

Поле с аннотацией игнорируется как при записи, так и при чтении JSON.

@AllArgsConstructor @NoArgsConstructor @Getter public class Dog
public class JacksonTest < . @Test void dogToJson() throws JsonProcessingException < Dog dog = new Dog("Max", 3); String json = objectMapper.writeValueAsString(dog); System.out.println(json); >>

То же самое относится и к чтению в POJO.

Предположим, у нас есть файл dog.json :

public class JacksonTest < . @Test void fileToDog() throws IOException < File file = new File("src/test/resources/dog.json"); Dog dog = objectMapper.readValue(file, Dog.class); assertThat(dog.getName()).isEqualTo("bobby"); assertThat(dog.getAge()).isNull(); >>

У Jackson есть еще много полезных аннотаций, которые дают нам больше контроля над процессом сериализации/десериализации. Полный их список можно найти в репозитории Jackson на Github.

Резюме

  • Jackson — одна из самых мощных и популярных библиотек для обработки JSON в Java.
  • Jackson включает три основных модуля: Streaming API, Tree Model и Data Binding.
  • Jackson предоставляет ObjectMapper, который легко настраивается в соответствии с потребностями, с возможностью задавать его свойства и использовать аннотации.

Приглашаем всех желающих на открытый урок «Реляционные базы данных для начинающих Java-разработчиков». На уроке поговорим о месте реляционных баз данных в архитектуре информационных систем. Рассмотрим основные компоненты и возможности РСУБД на примере PostgreSQL. Сделаем обзор основных технологий по работе с реляционными БД в Java (JDBC, JPA/Hibernate, Spring Data и др.). Регистрируйтесь по ссылке.

  • Блог компании OTUS
  • Программирование
  • Java

Парсинг JSON с помощью JSON simple -выдает ошибку. Не могу победить 2 день. Поможайте!

Всем доброго, друзья! У меня тут такая задачка, с которой бьюсь второй день и не могу победить. В чем может быть проблема, на ваш взгляд: 1) есть файл JSON:

 "tickets": [ "origin": "VVO", "origin_name": "Владивосток", "destination": "TLV", "destination_name": "Тель-Авив", "departure_date": "12.05.18", "departure_time": "16:20", "arrival_date": "12.05.18", "arrival_time": "22:10", "carrier": "TK", "stops": 3, "price": 12400 >,  "origin": "VVO", "origin_name": "Владивосток", "destination": "TLV", "destination_name": "Тель-Авив", "departure_date": "12.05.18", "departure_time": "6:10", "arrival_date": "12.05.18", "arrival_time": "16:15", "carrier": "S7", "stops": 0, "price": 17400 >] >

Пытаюсь его парсить так:

public static void main(String[] args) throws IOException, ParseException  Object obj = new JSONParser().parse(new FileReader("c:/tickets.json")); JSONObject jo = (JSONObject) obj; JSONArray ticketsArr = (JSONArray) jo.get("tickets"); Iterator ticketsItr = ticketsArr.iterator(); System.out.println("tickets:"); while (ticketsItr.hasNext())  JSONObject test = (JSONObject) ticketsItr.next(); System.out.println("- tickets: " + test.get("departure_time") ); > Постоянно выдает ошибку: "Exception in thread "main" Unexpected character () at position 0." Не могу понять, в чем беда... >

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *