Введение в API связывания JSON (JSR 367) в Java

1. Обзор

Долгое время не было стандарта для обработки JSON в Java. Наиболее распространенные библиотеки, используемые для обработки JSON - это Джексон и Гсон.

Недавно в Java EE7 был добавлен API для анализа и генерации JSON ( JSR 353: Java API для обработки JSON ).

И наконец, в выпуске JEE 8 появился стандартизированный API ( JSR 367: Java API для привязки JSON (JSON-B) ).

На данный момент его основные реализации - Eclipse Yasson (RI) и Apache Johnzon .

2. JSON-B API

2.1. Maven Dependency

Давайте начнем с добавления необходимой зависимости.

Имейте в виду, что во многих случаях будет достаточно включить зависимость для выбранной реализации, а javax.json.bind-api будет включен транзитивно:

<dependency>
    <groupId>javax.json.bind</groupId>
    <artifactId>javax.json.bind-api</artifactId>
    <version>1.0</version>
</dependency>

Самую последнюю версию можно найти по адресу Maven Central .

3. Использование Eclipse Yasson

  • Eclipse Yasson - официальная справочная реализация ** JSON Binding API ( JSR-367 ).

3.1. Maven Dependency

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

<dependency>
    <groupId>org.eclipse</groupId>
    <artifactId>yasson</artifactId>
    <version>1.0.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.json</artifactId>
    <version>1.1.2</version>
</dependency>

Самые последние версии можно найти по адресу Maven Central.

4. Использование Apache Johnzon

Другая реализация, которую мы можем использовать, - это Apache Johnzon, которая соответствует API-интерфейсам JSON-P (JSR-353) и JSON-B (JSR-367).

4.1. Maven Dependency

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

<dependency>
    <groupId>org.apache.geronimo.specs</groupId>
    <artifactId>geronimo-json__1.1__spec</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>org.apache.johnzon</groupId>
    <artifactId>johnzon-jsonb</artifactId>
    <version>1.1.4</version>
</dependency>

Самые последние версии можно найти по адресу Maven Central.

5. Особенности API

API предоставляет аннотации для настройки сериализации/десериализации.

Давайте создадим простой класс и посмотрим, как выглядит пример конфигурации:

public class Person {

    private int id;

    @JsonbProperty("person-name")
    private String name;

    @JsonbProperty(nillable = true)
    private String email;

    @JsonbTransient
    private int age;

    @JsonbDateFormat("dd-MM-yyyy")
    private LocalDate registeredDate;

    private BigDecimal salary;

    @JsonbNumberFormat(locale = "en__US", value = "#0.0")
    public BigDecimal getSalary() {
        return salary;
    }

   //standard getters and setters
}

После сериализации объект этого класса будет выглядеть так:

{
   "email":"[email protected]",
   "id":1,
   "person-name":"Jhon",
   "registeredDate":"07-09-2019",
   "salary":"1000.0"
}

Аннотации, используемые здесь:

  • @ JsonbProperty - который используется для указания имени настраиваемого поля

  • @ JsonbTransient - когда мы хотим игнорировать поле во время

десериализации/сериализации ** @ JsonbDateFormat - когда мы хотим определить формат отображения

Дата ** @ JsonbNumberFormat - для указания формата отображения числовых

ценности ** @ JsonbNillable - для включения сериализации нулевых значений

5.1. Сериализация и десериализация

Прежде всего, чтобы получить JSON-представление нашего объекта, нам нужно использовать класс JsonbBuilder и его метод toJson () .

Для начала давайте создадим простой объект Person , например:

Person person = new Person(
  1,
  "Jhon",
  "[email protected]",
  20,
  LocalDate.of(2019, 9, 7),
  BigDecimal.valueOf(1000));

И создайте экземпляр класса Jsonb :

Jsonb jsonb = JsonbBuilder.create();

Затем мы используем метод toJson :

String jsonPerson = jsonb.toJson(person);

Чтобы получить следующее представление JSON:

{
    "email":"[email protected]",
    "id":1,
    "person-name":"Jhon",
    "registeredDate":"07-09-2019",
    "salary":"1000.0"
}

Если мы хотим сделать преобразование другим способом, мы можем использовать метод fromJson :

Person person = jsonb.fromJson(jsonPerson, Person.class);

Естественно, мы также можем обрабатывать коллекции:

List<Person> personList = Arrays.asList(...);
String jsonArrayPerson = jsonb.toJson(personList);

Чтобы получить следующее представление JSON:

----[
    {
      "email":"[email protected]",
      "id":1,
      "person-name":"Jhon",
      "registeredDate":"09-09-2019",
      "salary":"1000.0"
    },
    {
      "email":"[email protected]",
      "id":2,
      "person-name":"Jhon",
      "registeredDate":"09-09-2019",
      "salary":"1500.0"
    },
    ...]----

Для преобразования массива JSON в List мы будем использовать API fromJson :

List<Person> personList = jsonb.fromJson(
  personJsonArray,
  new ArrayList<Person>(){}.getClass().getGenericSuperclass()
);

5.2. Настраиваемое сопоставление с JsonbConfig

Класс JsonbConfig позволяет нам настроить процесс отображения для всех классов.

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

Теперь мы будем использовать стратегию LOWER CASE WITH UNDERSCORES__:

JsonbConfig config = new JsonbConfig().withPropertyNamingStrategy(
  PropertyNamingStrategy.LOWER__CASE__WITH__UNDERSCORES);
Jsonb jsonb = JsonbBuilder.create(config);
String jsonPerson = jsonb.toJson(person);

Чтобы получить следующее представление JSON:

{
   "email":"[email protected]",
   "id":1,
   "person-name":"Jhon",
   "registered__date":"07-09-2019",
   "salary":"1000.0"
}

Теперь мы изменим порядок свойств с помощью стратегии REVERSE . Используя эту стратегию, порядок свойств в порядке, обратном лексикографическому. Это также можно настроить во время компиляции с помощью аннотации @JsonbPropertyOrder. Давайте посмотрим это в действии:

JsonbConfig config
  = new JsonbConfig().withPropertyOrderStrategy(PropertyOrderStrategy.REVERSE);
Jsonb jsonb = JsonbBuilder.create(config);
String jsonPerson = jsonb.toJson(person);

Чтобы получить следующее представление JSON:

{
    "salary":"1000.0",
    "registeredDate":"07-09-2019",
    "person-name":"Jhon",
    "id":1,
    "email":"[email protected]"
}

5.3. Пользовательское сопоставление с адаптерами

Когда нам недостаточно аннотаций и класса JsonbConfig , мы можем использовать адаптеры.

Чтобы их использовать, нам нужно реализовать интерфейс JsonbAdapter , который определяет следующие методы:

  • adaptToJson - С этим методом мы можем использовать собственную логику преобразования

для процесса сериализации.

  • adaptFromJson - Этот метод позволяет нам использовать собственную логику преобразования

для процесса десериализации.

Давайте создадим PersonAdapter для обработки атрибутов id и name класса Person :

public class PersonAdapter implements JsonbAdapter<Person, JsonObject> {

    @Override
    public JsonObject adaptToJson(Person p) throws Exception {
        return Json.createObjectBuilder()
          .add("id", p.getId())
          .add("name", p.getName())
          .build();
    }

    @Override
    public Person adaptFromJson(JsonObject adapted) throws Exception {
        Person person = new Person();
        person.setId(adapted.getInt("id"));
        person.setName(adapted.getString("name"));
        return person;
    }
}

Кроме того, мы назначим адаптер нашему экземпляру JsonbConfig :

JsonbConfig config = new JsonbConfig().withAdapters(new PersonAdapter());
Jsonb jsonb = JsonbBuilder.create(config);

И мы получим следующее представление JSON:

{
    "id":1,
    "name":"Jhon"
}

6. Заключение

В этом руководстве мы рассмотрели пример интеграции API JSON-B с приложениями Java с использованием доступных реализаций, а также примеры настройки сериализации и десериализации как во время компиляции, так и во время выполнения.

Полный код доступен, как всегда, over на Github .