В этом посте мы продолжим изучение XML и JSON в Java 11 и выше.
Примеры в этой статье познакомят вас с JSON-B,API привязки JSON для Java. После краткого обзора и инструкций по установке я покажу вам, как использовать JSON-B для сериализации и десериализации объектов, массивов и коллекций Java, как использовать JSON-B для настройки сериализации и десериализации и как использовать JSON-B. для сериализации и десериализации объектов Java Используйте адаптер JSON-B для преобразования исходного объекта в целевой во время сериализации или десериализации.
Материалы этой статьи новые, но их можно рассматривать как очередную главу моей новой книги (глава 13), недавно вышедшей в издательстве Apress:
.Что такое JSON-B?
JSON-B основан на JSON-P, API-интерфейсе обработки JSON для синтаксического анализа, создания, запроса и преобразования документов JSON. JSON-B создаетсяЗапрос спецификации Java (JSR) 367существуетJSR 353(JSR для JSON-P) был выпущен более чем через год после его окончательного выпуска.
JSON-B API
Привязка JSONизJava-API (JSON-B)Веб-сайт представляет JSON-B и предоставляет доступ к различным ресурсам, включаяДокументация API. Согласно документу, модуль JSON-B хранит шесть пакетов:
-
javax.json.bind
: определяет точку входа для привязки объектов Java к документам JSON. -
javax.json.bind.adapter
: определяет классы, связанные с адаптером. -
javax.json.bind.annotation
: аннотация, определяющая сопоставление между элементами программы Java и документами JSON. -
javax.json.bind.config
: определяет политики и стратегии для настройки сопоставления между элементами программы Java и документами JSON. -
javax.json.bind.serializer
: определяет интерфейс для создания пользовательских сериализаторов и десериализаторов. -
javax.json.bind.spi
: определяет интерфейс поставщика услуг (SPI) для подключения пользовательскихJsonbBuilder
.
Веб-сайт JSON-B также предоставляетYassonссылка на,Yasson— это платформа Java, которая обеспечивает стандартный уровень привязки между классами Java и документами JSON, а также официальную эталонную реализацию API привязки JSON.
Скачайте и установите JSON-B
JSON-B 1.0 является текущей версией на момент написания этой статьи. ты можешь начатьРепозиторий MavenПолучите эталонную реализацию этой библиотеки Yasson. Вам необходимо загрузить следующие файлы JAR:
-
Javax JSON Bind API 1.0: содержит все файлы классов JSON-B. Я скачал
javax.json.bind-api-1.0.jar
. -
Yasson: содержит эталонную реализацию JSON-B на основе Eclipse. Я скачал
yasson-1.0.3.jar
. -
JSR 374 (обработка JSON) Поставщик по умолчанию: содержит все файлы классов JSON-P 1.0, а также файлы классов поставщиков по умолчанию для Glassfish. Я скачал
javax.json-1.1.4.jar
.
Добавьте эти JAR-файлы в путь к классам при компиляции и запуске кода, использующего эти библиотеки:
javac -cp javax.json.bind-api-1.0.jar;. main source file
java -cp javax.json.bind-api-1.0.jar;yasson-1.0.3.jar;javax.json-1.1.4.jar;. main classfile
Сериализация и десериализация объектов Java с использованием JSON-B
Долженjavax.json.bind
пакет предоставляетJsonb
а такжеJsonbBuilder
интерфейсы, которые действуют как точки входа для этой библиотеки:
-
Jsonb
при условииtoJson()
перегруженные методы для сериализации дерева объектов Java в документы JSON иfromJson()
Методы десериализации документов JSON в деревья объектов Java. -
JsonbBuilder
поставкаnewBuilder()
и другие способы получения новой сборки, а такжеbuild()
а такжеcreate()
вернуть новый методJsonb
Объект.
Следующий пример кода демонстрируетJsonb
а такжеJsonBuilder
Основное использование типов:
// Create a new Jsonb instance using the default JsonbBuilder implementation.
Jsonb jsonb = JsonbBuilder.create();
// Create an Employee object from a hypothetical Employee class.
Employee employee = ...
// Convert the Employee object to a JSON document stored in a string.
String jsonEmployee = jsonb.toJson(employee);
// Convert the previously-created JSON document to an Employee object.
Employee employee2 = jsonb.fromJson(jsonEmployee, Employee.class);
В этом примере вызывается сериализация объектов Java.Jsonb
изString toJson(Object object)
метод(Employee
). Этому методу передается корень дерева объектов Java для сериализации. еслиnull
пройти, тоtoJson()
бросатьjava.lang.NullPointerException
. Он выдает, когда во время сериализации возникают непредвиденные проблемы (например, ошибки ввода-вывода).javax.json.bind.JsonbException
.
Этот фрагмент также вызываетJsonb
из<T> T fromJson(String str, Class<T> type)
Общий метод, который используется для десериализации. Этот метод передает строковый документ JSON для десериализации и возвращает тип корневого объекта результирующего дерева объектов Java. Любой параметр, переданный этому методу,null
бросили, когдаNullPointerException
; Когда во время десериализации возникают неожиданные проблемыJsonbException
.
я изJSONBDemo
Фрагменты кода взяты из приложения, которое предоставляет базовую демонстрацию JSON-B. В листинге 1 показан исходный код этой демонстрации.
Листинг 1. JSONBDemo.java (версия 1)
import java.time.LocalDate;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class JSONBDemo
{
public static void main(String[] args)
{
Jsonb jsonb = JsonbBuilder.create();
Employee employee = new Employee("John", "Doe", 123456789, false,
LocalDate.of(1980, 12, 23),
LocalDate.of(2002, 8, 14));
String jsonEmployee = jsonb.toJson(employee);
System.out.println(jsonEmployee);
System.out.println();
Employee employee2 = jsonb.fromJson(jsonEmployee, Employee.class);
System.out.println(employee2);
}
}
main()
Сначала создайтеJsonb
объект, за которым следуетEmployee
объект. Затем он вызываетtoJson()
БудуEmployee
Объекты сериализуются в документы JSON, хранящиеся в строках. После печати документаmain()
передачаfromJson()
и десериализовать строку вEmployee
.
Листинг 2. Employee.java (версия 1)
import java.time.LocalDate;
public class Employee
{
private String firstName;
private String lastName;
private int ssn;
private boolean isMarried;
private LocalDate birthDate;
private LocalDate hireDate;
private StringBuffer sb = new StringBuffer();
public Employee() {}
public Employee(String firstName, String lastName, int ssn, boolean isMarried,
LocalDate birthDate, LocalDate hireDate)
{
this.firstName = firstName;
this.lastName = lastName;
this.ssn = ssn;
this.isMarried = isMarried;
this.birthDate = birthDate;
this.hireDate = hireDate;
}
public String getFirstName()
{
return firstName;
}
public String getLastName()
{
return lastName;
}
public int getSSN()
{
return ssn;
}
public boolean isMarried()
{
return isMarried;
}
public LocalDate getBirthDate()
{
return birthDate;
}
public LocalDate getHireDate()
{
return hireDate;
}
public void setFirstName(String firstName)
{
this.firstName = firstName;
}
public void setLastName(String lastName)
{
this.lastName = lastName;
}
public void setSSN(int ssn)
{
this.ssn = ssn;
}
public void setIsMarried(boolean isMarried)
{
this.isMarried = isMarried;
}
public void setBirthDate(LocalDate birthDate)
{
this.birthDate = birthDate;
}
public void setHireDate(LocalDate hireDate)
{
this.hireDate = hireDate;
}
@Override
public String toString()
{
sb.setLength(0);
sb.append("First name [");
sb.append(firstName);
sb.append("], Last name [");
sb.append(lastName);
sb.append("], SSN [");
sb.append(ssn);
sb.append("], Married [");
sb.append(isMarried);
sb.append("], Birthdate [");
sb.append(birthDate);
sb.append("], Hiredate [");
sb.append(hireDate);
sb.append("]");
return sb.toString();
}
}
Подготовьте списки 1 и 2 следующим образом:
javac -cp javax.json.bind-api-1.0.jar;. JSONBDemo.java
Запустите приложение следующим образом:
java -cp javax.json.bind-api-1.0.jar;yasson-1.0.3.jar;javax.json-1.1.4.jar;. JSONBDemo
Вы должны наблюдать следующий вывод (разнесенный на несколько строк для удобочитаемости):
{"SSN":123456789,"birthDate":"1980-12-23","firstName":"John","hireDate":"2002-08-14",
"lastName":"Doe","married":false}
First name [John], Last name [Doe], SSN [123456789], Married [false],
Birthdate [1980-12-23], Hiredate [2002-08-14]
Правила использования JSON-B
Играя с этим приложением, я заметил некоторые интересные особенности поведения, которые заставили меня сформулировать следующее оEmployee
правило:
- класс должен быть
public
; В противном случае выбрасывается исключение. -
toJson()
не будет использоватьpublic
Метод получения сериализует поле. -
fromJson()
не будет использоватьpublic
Метод установки десериализует поле. -
fromJson()
В отсутствиеpublic no argument
Кейс конструктора кидаетJsonbException
.
Для беспрепятственного преобразования между полями объекта Java и данными JSON JSON-B должен поддерживать различные типы Java. Например, JSON-B поддерживает следующие основные типы Java:
java.lang.Boolean
java.lang.Byte
java.lang.Character
java.lang.Double
java.lang.Float
java.lang.Integer
java.lang.Long
java.lang.Short
java.lang.String
другие типы, такие какjava.math.BigInteger
,java.util.Date
а такжеjava.time.LocalDate
служба поддержки. ПроверитьСпецификация JSON-Bполный список поддерживаемых типов.
Сериализация и десериализация массивов и коллекций с использованием JSON-B
В предыдущем разделе основное внимание уделялось сериализации и десериализации одного объекта Java. JSON-B также поддерживает возможность сериализации и десериализации массивов и коллекций объектов. В листинге 3 представлена демонстрация.
Листинг 3. JSONBDemo.java (версия 2)
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
public class JSONBDemo
{
public static void main(String[] args)
{
arrayDemo();
listDemo();
}
// Serialize and deserialize an array of Employee objects.
static void arrayDemo()
{
Jsonb jsonb = JsonbBuilder.create();
Employee[] employees =
{
new Employee("John", "Doe", 123456789, false,
LocalDate.of(1980, 12, 23),
LocalDate.of(2002, 8, 14)),
new Employee("Jane", "Smith", 987654321, true,
LocalDate.of(1982, 6, 13),
LocalDate.of(2001, 2, 9))
};
String jsonEmployees = jsonb.toJson(employees);
System.out.println(jsonEmployees);
System.out.println();
employees = null;
employees = jsonb.fromJson(jsonEmployees, Employee[].class);
for (Employee employee: employees)
{
System.out.println(employee);
System.out.println();
}
}
// Serialize and deserialize a List of Employee objects.
static void listDemo()
{
Jsonb jsonb = JsonbBuilder.create();
List<Employee> employees =
Arrays.asList(new Employee("John", "Doe", 123456789, false,
LocalDate.of(1980, 12, 23),
LocalDate.of(2002, 8, 14)),
new Employee("Jane", "Smith", 987654321, true,
LocalDate.of(1982, 6, 13),
LocalDate.of(1999, 7, 20)));
String jsonEmployees = jsonb.toJson(employees);
System.out.println(jsonEmployees);
System.out.println();
employees = null;
employees = jsonb.fromJson(jsonEmployees,
new ArrayList<>(){}.
getClass().getGenericSuperclass());
System.out.println(employees);
}
}
Листинг 3 представляет собой простое расширение таблицы 1 и использует тот жеEmployee
Листинг 2. Кроме того, в классе рендеринга этот пример кода иtoJson()
а такжеfromJson()
Вызов метода тот же.
Когда документ JSON десериализует массив объектов Java, выражениеEmployee[].class
передается в качестве второго параметра вfromJson()
, чтобы он мог создать соответствующий массив. При десериализации объекта JSON в список или другую коллекцию выражениеnew ArrayList<>(){}.getClass().getGenericSuperclass()
Передается как второй параметр. JDK 11 сделает выводEmployee
, поэтому мне не нужно указыватьArrayList<Employee>
.
В идеале должна быть возможность пройтиArrayList<Employee>.class
, сообщитьfromJson()
Набор ожидаемых параметров типа для создания экземпляра. Однако из-застирание типа, это выражение недопустимо. Вместо этого я могу указатьArrayList.class
который будет работать. Однако он также генерирует непроверенные предупреждающие сообщения. Чем сложнее выражение, тем меньше предупреждений будет генерироваться. По сути, он создает анонимный подклассArrayList<Employee>
, получить егоClass
объект и использоватьClass
Объекты, чтобы получить тип параметризации его суперцентов, это происходитArrayList<Employee>
. Этот параметризованный тип можно использовать дляfromJson()
.
Скомпилируйте листинги 3 и 2 и запустите получившееся приложение. Вы должны наблюдать следующий вывод (разнесенный на несколько строк для удобочитаемости):
[{"SSN":123456789,"birthDate":"1980-12-23","firstName":"John","hireDate":"2002-08-14",
"lastName":"Doe","married":false},
{"SSN":987654321,"birthDate":"1982-06-13","firstName":"Jane","hireDate":"2001-02-09",
"lastName":"Smith","married":true}]
First name [John], Last name [Doe], SSN [123456789], Married [false],
Birthdate [1980-12-23], Hiredate [2002-08-14]
First name [Jane], Last name [Smith], SSN [987654321], Married [false],
Birthdate [1982-06-13], Hiredate [2001-02-09]
[{"SSN":123456789,"birthDate":"1980-12-23","firstName":"John","hireDate":"2002-08-14",
"lastName":"Doe","married":false},
{"SSN":987654321,"birthDate":"1982-06-13","firstName":"Jane","hireDate":"1999-07-20",
"lastName":"Smith","married":true}]
[{firstName=John, lastName=Doe, hireDate=2002-08-14, birthDate=1980-12-23, married=false,
SSN=123456789},
{firstName=Jane, lastName=Smith, hireDate=1999-07-20, birthDate=1982-06-13, married=true,
SSN=987654321}]
Пользовательская сериализация и десериализация в JSON-B
Хотя JSON-B многое делает для вас, поддерживая различные типы Java, вам может потребоваться настроить его поведение, например изменить порядок вывода сериализованных свойств. JSON-B поддерживает настройку времени компиляции и выполнения.
настройка во время компиляции
JSON-B через егоjavax.json.bind.annotation
Различные типы аннотаций в пакете поддерживают настройку во время компиляции. Например, вы можете использоватьJsonbDateFormat
Укажите пользовательский формат даты и изменитеJsonbProperty
Имя поля. Листинг 4Employee
Оба типа аннотаций описаны в классе.
Листинг 4. Employee.java (версия 2)
import java.time.LocalDate;
import javax.json.bind.annotation.JsonbDateFormat;
import javax.json.bind.annotation.JsonbProperty;
public class Employee
{
@JsonbProperty("first-name")
private String firstName;
@JsonbProperty("last-name")
private String lastName;
private int ssn;
private boolean isMarried;
@JsonbDateFormat("MM-dd-yyyy")
private LocalDate birthDate;
@JsonbDateFormat("MM-dd-yyyy")
private LocalDate hireDate;
private StringBuffer sb = new StringBuffer();
public Employee() {}
public Employee(String firstName, String lastName, int ssn, boolean isMarried,
LocalDate birthDate, LocalDate hireDate)
{
this.firstName = firstName;
this.lastName = lastName;
this.ssn = ssn;
this.isMarried = isMarried;
this.birthDate = birthDate;
this.hireDate = hireDate;
}
public String getFirstName()
{
return firstName;
}
public String getLastName()
{
return lastName;
}
public int getSSN()
{
return ssn;
}
public boolean isMarried()
{
return isMarried;
}
public LocalDate getBirthDate()
{
return birthDate;
}
public LocalDate getHireDate()
{
return hireDate;
}
public void setFirstName(String firstName)
{
this.firstName = firstName;
}
public void setLastName(String lastName)
{
this.lastName = lastName;
}
public void setSSN(int ssn)
{
this.ssn = ssn;
}
public void setIsMarried(boolean isMarried)
{
this.isMarried = isMarried;
}
public void setBirthDate(LocalDate birthDate)
{
this.birthDate = birthDate;
}
public void setHireDate(LocalDate hireDate)
{
this.hireDate = hireDate;
}
@Override
public String toString()
{
sb.setLength(0);
sb.append("First name [");
sb.append(firstName);
sb.append("], Last name [");
sb.append(lastName);
sb.append("], SSN [");
sb.append(ssn);
sb.append("], Married [");
sb.append(isMarried);
sb.append("], Birthdate [");
sb.append(birthDate);
sb.append("], Hiredate [");
sb.append(hireDate);
sb.append("]");
return sb.toString();
}
}
для листинга 4JsonbProperty
ПримечанияfirstName
а такжеlastName
поле и использоватьJsonbDateFormat
ПримечанияbirthDate
а такжеhireDate
поле.JsonbProperty
Привести кfirstName
сериализовать вfirst-name
а такжеlastName
сериализовать вlast-name
. Этот тип аннотации также вызываетfirst-name
десериализоватьfirstName
а такжеlast-name
десериализоватьlastName
.JsonbDateFormat
Заставляет дни рождения и даты найма быть сериализованными в формате месяц-день-год вместо порядка год-месяц-день по умолчанию и заставляет JSON-B учитывать сериализованные порядок месяц-день-год при десериализации.
Листинг 1 и листинг 4 для компиляции и запуска сгенерированного приложения. Вы должны наблюдать следующий вывод (разнесенный на несколько строк для удобочитаемости):
{"SSN":123456789,"birthDate":"12-23-1980","first-name":"John","hireDate":"08-14-2002",
"last-name":"Doe","married":false}
First name [John], Last name [Doe], SSN [123456789], Married [false],
Birthdate [1980-12-23], Hiredate [2002-08-14]
настройка среды выполнения
JSON-B проходjavax.json.bind.JsonbConfig
а такжеJsonbBuilder
Поддерживается настройка среды выполнения. в случаеJsonbConfig
, называя различныеwith
XXX методы (например,withPropertyOrderStrategy
) для настройки задачи и выполнения конфигурацииJsonbConfig
предоставляется на объектJsonBuilder
, возможно, используя его какJsonbBuilder
изstatic Jsonb create(JsonbConfig config)
параметры метода. Ознакомьтесь с листингом 5.
Листинг 5. JSONBDemo.java (версия 3)
import java.time.LocalDate;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
import static javax.json.bind.config.PropertyOrderStrategy.*;
public class JSONBDemo
{
public static void main(String[] args)
{
JsonbConfig config = new JsonbConfig()
.withPropertyOrderStrategy(REVERSE);
Jsonb jsonb = JsonbBuilder.create(config);
Employee employee = new Employee("John", "Doe", 123456789, false,
LocalDate.of(1980, 12, 23),
LocalDate.of(2002, 8, 14));
String jsonEmployee = jsonb.toJson(employee);
System.out.println(jsonEmployee);
System.out.println();
Employee employee2 = jsonb.fromJson(jsonEmployee, Employee.class);
System.out.println(employee2);
}
}
Листинг 5main()
Во-первых, призракJsonbConfig
а затем вызовите этот классJsonbConfig withPropertyOrderStrategy(String propertyOrderStrategy)
способ изменить стратегию порядка свойств наjavax.json.bind.config.PropertyOrderStrategy.REVERSE
. Этот порядок политики приводит к тому, что атрибуты выводятся в порядке, обратном их обычному выводу.
ДолженJsonbConfig
объект передается вcreate(JsonbConfig)
полученная конфигурацияJsonb
объектJsonbBuilder
наконец вернуться. В остальном метод такой же, как показано в листинге 1.
Скомпилируйте листинги 2 и 5, затем запустите получившееся приложение. Вы должны наблюдать следующий вывод (разнесенный на несколько строк для удобочитаемости):
{"married":false,"lastName":"Doe","hireDate":"2002-08-14","firstName":"John",
"birthDate":"1980-12-23","SSN":123456789}
First name [John], Last name [Doe], SSN [123456789], Married [false],
Birthdate [1980-12-23], Hiredate [2002-08-14]
Вы можете выполнить ту же задачу обратного упорядочения свойств, используя один из типов аннотаций JSON-B. Я оставлю это, чтобы выяснить, как делать это упражнение.
Использование адаптеров в JSON-B
Наконец, поддержка JSON-B
Адаптер состоит из необработанного объекта Java, объекта адаптации/преобразования, содержащего измененные/дополнительные поля, и объекта адаптера, который являетсяjavax.json.bind.adapter.Adapter<Original,Adapted>
экземпляр типа.
ДолженAdapter
Тип предоставляет следующие методы:
-
Original adaptFromJson(Adapted obj)
: этот метод вызывается во время десериализации для преобразованияAdapted
дляOriginal
. -
Adapted adaptToJson(Original obj)
: этот метод вызывается во время сериализации для преобразованияOriginal
дляAdapted
, затем сериализуйте его в JSON.
Оба метода используютthrows Exception
объявление пункта о том, что он может генерировать любое исключение во время преобразования.
В листинге 6 приведен исходный кодIdentityAdapter
, адаптер, который ничего не меняет. Однако он выводит объект, который мог быть изменен, и демонстрирует архитектуру адаптера.
Листинг 6. IdentityAdapter.java
import javax.json.bind.adapter.JsonbAdapter;
public class IdentityAdapter implements JsonbAdapter<Employee, Employee>
{
@Override
public Employee adaptFromJson(Employee obj)
{
System.out.println("Deserializing: " + obj);
return obj;
}
@Override
public Employee adaptToJson(Employee obj)
{
System.out.println("Serializing: " + obj);
return obj;
}
}
ты используешьJsonbConfig
а такжеJsonbConfig withAdapters(JsonbAdapter...)
метод для регистрации одного или нескольких адаптеров:
JsonbConfig config = new JsonbConfig()
.withAdapters(new IdentityAdapter());
Этот объект передаетсяJsonbBuilder
изcreate(JsonbConfig)
метод, как я показал ранее. Для полнотыJSONBDemo
Исходный код демонстрирует обе задачи.
Листинг 7. JSONBDemo.java (версия 4)
import java.time.LocalDate;
import javax.json.bind.Jsonb;
import javax.json.bind.JsonbBuilder;
import javax.json.bind.JsonbConfig;
public class JSONBDemo
{
public static void main(String[] args)
{
JsonbConfig config = new JsonbConfig()
.withAdapters(new IdentityAdapter());
Jsonb jsonb = JsonbBuilder.create(config);
Employee employee = new Employee("John", "Doe", 123456789, false,
LocalDate.of(1980, 12, 23),
LocalDate.of(2002, 8, 14));
String jsonEmployee = jsonb.toJson(employee);
System.out.println(jsonEmployee);
System.out.println();
Employee employee2 = jsonb.fromJson(jsonEmployee, Employee.class);
System.out.println(employee2);
}
}
Скомпилируйте листинги 2, 6 и 7 и запустите получившееся приложение. Вы должны наблюдать следующий вывод (разнесенный на несколько строк для удобочитаемости):
Serializing: First name [John], Last name [Doe], SSN [123456789], Married [false],
Birthdate [1980-12-23], Hiredate [2002-08-14]
{"SSN":123456789,"birthDate":"1980-12-23","firstName":"John","hireDate":"2002-08-14",
"lastName":"Doe","married":false}
Deserializing: First name [John], Last name [Doe], SSN [123456789], Married [false],
Birthdate [1980-12-23], Hiredate [2002-08-14]
First name [John], Last name [Doe], SSN [123456789], Married [false],
Birthdate [1980-12-23], Hiredate [2002-08-14]
В заключение
JSON-B прекрасно дополняет JSON-P, и яГлава 12,
Я уверен, что JSON-B продолжит развиваться и может стать отличным дополнением к третьему изданию моей книги. А пока я рекомендую вам узнать больше о JSON-B, изучив различные методы и типы аннотаций, не рассмотренные в этой статье.
Английский оригинал:Woohoo. Java world.com/article/335…
Посмотреть другие статьи: www.apexyun.com
Общедоступный номер: Galaxy № 1
Контактный адрес электронной почты: public@space-explore.com
(Пожалуйста, не перепечатывайте без разрешения)