Accept json in java

Чтение и запись JSON на Java

Обозначение объектов JavaScript или, короче говоря, JSON -это формат обмена данными, который был введен в 1999 году и получил широкое распространение в середине 2000-х годов. В настоящее время это де-факто стандартный формат для общения между веб-сервисами и их клиентами (браузерами, мобильными приложениями и т.д.). Знание того, как читать и писать, является необходимым навыком для любого разработчика программного обеспечения.

Несмотря на то, что ДЖЕЙСОН был получен из JavaScript, это независимый от платформы формат. Вы можете работать с ним на нескольких языках программирования, включая Java, Python, Ruby и многие другие. Действительно, любой язык, который может анализировать строку, может обрабатывать JSON.

Популярность JSON привела к его встроенной поддержке многими базами данных, последние версии PostgreSQL и MySQL содержат встроенную поддержку запроса данных, хранящихся в полях JSON. Базы данных NoSQL, такие как MongoDB , были построены на основе этого формата и используют документы JSON для хранения записей, точно так же, как таблицы и строки хранят записи в реляционной базе данных.

Одним из основных преимуществ JSON по сравнению с форматом данных XML является размер документа. Поскольку JSON не имеет схем, нет необходимости переносить огромные структурные накладные расходы, такие как пространства имен и оболочки.

JSON-это универсальный формат данных, который имеет шесть типов данных:

Давайте взглянем на простой документ JSON:

Эта структура определяет объект, представляющий человека по имени “Бенджамин Уотсон”. Здесь мы можем ознакомиться с его подробностями, такими как его возраст, семейное положение и хобби.

Читайте также:  The keyword this in java

По сути, объект JSON – это не более чем строка. Строка, представляющая объект, поэтому объекты JSON часто называются Строками JSON или документами JSON .

json-просто

Поскольку в Java нет встроенной поддержки JSON, прежде всего, мы должны добавить новую зависимость, которая обеспечивала бы ее для нас. Для начала мы будем использовать модуль json-simple , добавив его в качестве зависимости Maven.

 com.googlecode.json-simple json-simple 

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

Давайте создадим простой метод, который будет принимать имя файла в качестве параметра и записывать некоторые жестко закодированные данные JSON:

public static void writeJsonSimpleDemo(String filename) throws Exception

Здесь мы создаем экземпляр класса JSONObject , указывая имя и возраст в качестве свойств. Затем мы создаем экземпляр класса JSONArray , добавляя два строковых элемента и помещая его в качестве третьего свойства нашего sampleObject . В конечном счете, мы преобразуем образец объекта в документ JSON, вызывающий метод toJSONString() и записываем его в файл.

Чтобы запустить этот код, мы должны создать точку входа в наше приложение, которая могла бы выглядеть следующим образом:

В результате выполнения этого кода мы получим файл с именем example.json в корне нашего пакета. Содержимое файла будет документом JSON со всеми свойствами, которые мы ввели:

Отлично! У нас только что был наш первый опыт работы с форматом JSON, и мы успешно сериализовали в него объект Java и записали его в файл.

Теперь, с небольшим изменением нашего исходного кода, мы можем прочитать объект JSON из файла и распечатать его на консоли либо полностью, либо распечатать выбранные отдельные свойства:

public static void main(String[] args) throws Exception < JSONObject jsonObject = (JSONObject) readJsonSimpleDemo("example.json"); System.out.println(jsonObject); System.out.println(jsonObject.get("age")); >public static Object readJsonSimpleDemo(String filename) throws Exception

Важно отметить, что метод parse() возвращает Объект , и мы должны явно привести его к JSONObject .

Если у вас неправильный или поврежденный документ JSON, вы получите исключение, подобное этому:

Exception in thread "main" Unexpected token END OF FILE at position 64.

Чтобы смоделировать это, попробуйте удалить последнюю закрывающую скобку > .

Копать Глубже

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

kids) < this.name = name; this.age = age; this.isMarried = isMarried; this.hobbies = hobbies; this.kids = kids; >Person(String name, int age) < this(name, age, false, null, null); >private String name; private Integer age; private Boolean isMarried; private List hobbies; private List

kids; // getters and setters @Override public String toString()

Нашей задачей было бы десериализовать этот объект из файла в экземпляр класса Person . Давайте сначала попробуем сделать это с помощью simple-json .

Изменив наш метод main () , повторно используя статический readSimpleJsonDemo() и добавив необходимый импорт, мы доберемся до:

public static void main(String[] args) throws Exception < JSONObject jsonObject = (JSONObject) readJsonSimpleDemo("example.json"); Person ben = new Person( (String) jsonObject.get("name"), Integer.valueOf(jsonObject.get("age").toString()), (Boolean) jsonObject.get("isMarried"), (List) jsonObject.get("hobbies"), (List) jsonObject.get("kids")); System.out.println(ben); > 

Это выглядит не очень хорошо, у нас много странных типов, но, похоже, это делает свою работу, верно?

Git Essentials

Ознакомьтесь с этим практическим руководством по изучению Git, содержащим лучшие практики и принятые в отрасли стандарты. Прекратите гуглить команды Git и на самом деле изучите это!

Давайте попробуем распечатать на консоли массив дети нашего Человека , а затем возраст первого ребенка.

System.out.println(ben.getKids()); System.out.println(ben.getKids().get(0).getAge());

Как мы видим, первый вывод консоли показывает, казалось бы, хороший результат:

но второй выдает Исключение :

Exception in thread "main" java.lang.ClassCastException: org.json.simple.JSONObject cannot be cast to com.stackabuse.json.Person

Проблема здесь в том, что наш тип в Список не создал два новых Человека объекта, он просто вставил все, что там было – JSONObject в нашем текущем случае. Когда мы попытались копнуть глубже и узнать фактический возраст первого ребенка, мы столкнулись с ClassCastException .

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

Джексон

Библиотека, которая позволит нам делать все это очень эффективно, называется Джексон . Это очень распространено и используется в крупных корпоративных проектах, таких как Спящий режим .

Давайте добавим его в качестве новой зависимости Maven:

 com.fasterxml.jackson.core jackson-databind 

Основной класс , который мы будем использовать, называется ObjectMapper , у него есть метод readValue () , который принимает два аргумента: источник для чтения и класс для приведения результата.

ObjectMapper может быть настроен с несколькими различными параметрами, переданными в конструктор:

FAIL_ON_SELF_РЕФЕРЕНЦИИ Функция, которая определяет, что происходит, когда прямая самоссылка обнаруживается POJO (и для нее не включена обработка идентификатора объекта): либо создается исключение JsonMappingException (если это правда), либо ссылка обычно обрабатывается (ложь).
ОТСТУП_ВЫХОД Функция, которая позволяет включать (или отключать) отступы для базового генератора, используя принтер pretty по умолчанию, настроенный для ObjectMapper (и авторов объектов, созданных из mapper).
ORDER_MAP_ENTRIES_BY_KEYES Функция, определяющая, будут ли записи карты сначала отсортированы по ключу перед сериализацией или нет: если включено, при необходимости выполняется дополнительный шаг сортировки (не требуется для отсортированных карт), если отключено, дополнительная сортировка не требуется.
USE_EQUALITY_FOR_OBJECT_ID Функция, определяющая, сравнивается ли идентичность объекта с использованием истинной идентичности объекта на уровне JVM (ложь); или метод equals ().
Функция, определяющая, как сериализуется тип char []: при включении сериализуется как явный массив JSON (с односимвольными строками в качестве значений); при отключении по умолчанию сериализуется как строки (что более компактно).
МЕТКИ ВРЕМЕНИ WRITE_DATE_KEYS_AS_TIMESTAMPS Функция, определяющая, будут ли даты (и подтипы), используемые в качестве ключей карты, сериализованы как метки времени или нет (если нет, будут сериализованы как текстовые значения).
WRITE_DATE_TIMESTAMPS_АС_НАНОСЕКУНДЫ Функция, которая определяет, следует ли записывать числовые значения временных меток с использованием наносекундных временных меток (включено) или нет (отключено); если и только если тип данных поддерживает такое разрешение.
МЕТКИ ВРЕМЕНИ WRITE_DATES_AS_TIMESTAMPS Функция, которая определяет, следует ли сериализовать значения даты (и даты/времени) (и такие вещи, основанные на данных, как календари), как числовые метки времени (true; по умолчанию) или как что-то другое (обычно текстовое представление).
WRITE_DATES_С_ЗОНОМ_ИД Функция, которая определяет, следует ли сериализовать значения даты/времени так, чтобы они включали идентификатор часового пояса, в тех случаях, когда сам тип содержит информацию о часовом поясе.

Полный список сериализации перечисления доступен здесь .

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

К сожалению, после запуска этого фрагмента кода мы получим исключение:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.stackabuse.json.Person]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)

Судя по всему, мы должны добавить конструктор по умолчанию в класс Person :

При повторном запуске кода мы увидим еще одно исключение:

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "isMarried" (class com.stackabuse.json.Person), not marked as ignorable (5 known properties: "hobbies", "name", "married", "kids", "age"])

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

Проблема здесь связана с внутренней структурой библиотеки Джексона. Он выводит имена свойств из геттеров, удаляя их первые части. В случае getafe() и getName() это работает отлично, но с женат() это не так, и предполагается, что поле должно называться женат вместо Женат .

Грубый, но рабочий вариант – мы можем решить эту проблему, просто переименовав получателя в is Женат . Давайте продолжим и попробуем это сделать.

Больше никаких исключений не появляется, и мы видим желаемый результат!

Person, Person]> [Person, Person] 5

Хотя результат удовлетворяет, есть лучший способ обойти это, чем добавлять еще один is к каждому из ваших логических геттеров.

Мы можем достичь того же результата, добавив аннотацию к методу женат() :

Таким образом, мы явно сообщаем Джексону название поля, и ему не нужно угадывать. Это может быть особенно полезно в тех случаях, когда поле называется совершенно иначе, чем геттеры.

Вывод

JSON-это легкий текстовый формат, который позволяет нам представлять объекты и передавать их через Интернет или хранить в базе данных.

В Java отсутствует встроенная поддержка манипуляций с JSON, однако существует несколько модулей, обеспечивающих эту функциональность. В этом уроке мы рассмотрели модули json-simple и Jackson , показав сильные и слабые стороны каждого из них.

Работая с JSON, вы должны иметь в виду нюансы модулей, с которыми вы работаете, и тщательно отлаживать исключения, которые могут появляться.

Читайте ещё по теме:

Источник

Оцените статью