1. Обзор
В этом кратком руководстве мы покажем два различных способа десериализации неизменяемых объектов Java с помощью библиотеки обработки Jackson JSON.
2. Почему Мы Используем Неизменяемые Объекты?
Неизменяемый объект – это объект, который сохраняет свое состояние нетронутым с самого момента его создания . Это означает, что независимо от того, какие методы объекта вызывает конечный пользователь, объект ведет себя одинаково .
Неизменяемые объекты пригодятся , когда мы проектируем систему, которая должна работать в многопоточной среде , поскольку неизменность обычно гарантирует безопасность потоков.
С другой стороны, неизменяемые объекты полезны, когда нам нужно обрабатывать входные данные из внешних источников. Например, это может быть пользовательский ввод или некоторые данные из хранилища. В этом случае может иметь решающее значение для сохранения полученных данных и защиты их от случайных или непреднамеренных изменений .
Давайте посмотрим, как мы можем десериализовать неизменяемый объект.
3. Публичный конструктор
Давайте рассмотрим структуру классов Employee . Он имеет два обязательных поля: id и name , таким образом, мы определяем общедоступный конструктор всех аргументов , который имеет набор аргументов, соответствующий набору полей объекта:
public class Employee { private final long id; private final String name; public Employee(long id, String name) { this.id = id; this.name = name; } // getters }
Таким образом, все поля объекта будут инициализированы в момент создания. Окончательные модификаторы в объявлении полей не позволят нам изменить их значения в будущем. Чтобы сделать этот объект десериализуемым, нам просто нужно добавить пару аннотаций в этот конструктор:
@JsonCreator(mode = JsonCreator.Mode.PROPERTIES) public Employee(@JsonProperty("id") long id, @JsonProperty("name") String name) { this.id = id; this.name = name; }
Давайте подробнее рассмотрим аннотации, которые мы только что добавили.
Прежде всего, @JsonCreator говорит десериализатору Джексона использовать назначенный конструктор для десериализации .
Есть два режима, которые можно использовать в качестве параметра для этой аннотации – СВОЙСТВА и ДЕЛЕГИРОВАНИЕ .
СВОЙСТВА наиболее подходит, когда мы объявляем конструктор всех аргументов, в то время как ДЕЛЕГИРОВАНИЕ может быть полезно для конструкторов с одним аргументом.
После этого нам нужно аннотировать каждый из аргументов конструктора с помощью @JsonProperty , указав имя соответствующего свойства в качестве значения аннотации. Мы должны быть очень осторожны на этом этапе, так как все имена свойств должны совпадать с теми, которые мы использовали во время сериализации.
Давайте рассмотрим простой модульный тест, который охватывает десериализацию объекта Employee :
String json = "{\"name\":\"Frank\",\"id\":5000}"; Employee employee = new ObjectMapper().readValue(json, Employee.class); assertEquals("Frank", employee.getName()); assertEquals(5000, employee.getId());
4. Частный конструктор и Строитель
Иногда бывает так, что объект имеет набор необязательных полей. Давайте рассмотрим другую структуру классов, Person , которая имеет необязательное поле age :
public class Person { private final String name; private final Integer age; // getters }
Когда у нас есть значительное количество таких полей, создание общедоступного конструктора может стать громоздким . Другими словами, нам нужно будет объявить множество аргументов для конструктора и аннотировать каждый из них с помощью @JsonProperty аннотаций. В результате многие повторяющиеся объявления сделают наш код раздутым и трудным для чтения.
Это тот случай, когда на помощь приходит классический шаблон Builder . Давайте посмотрим, как мы можем использовать его силу в десериализации. Прежде всего, давайте объявим частный конструктор всех аргументов и Конструктор класс :
private Person(String name, Integer age) { this.name = name; this.age = age; } static class Builder { String name; Integer age; Builder withName(String name) { this.name = name; return this; } Builder withAge(Integer age) { this.age = age; return this; } public Person build() { return new Person(name, age); } }
Чтобы заставить десериализатор Джексона использовать этот Builder , нам просто нужно добавить две аннотации к нашему коду. Прежде всего, нам нужно пометить наш класс аннотацией @JsonDeserialize , передав параметр builder с полным доменным именем класса builder .
После этого нам нужно аннотировать сам класс builder как @JsonPOJOBuilder :
@JsonDeserialize(builder = Person.Builder.class) public class Person { //... @JsonPOJOBuilder static class Builder { //... } }
Обратите внимание, что мы можем настроить имена методов, используемых во время сборки.
Параметр Buildmethod name по умолчанию имеет значение ” build” и обозначает имя метода , который мы вызываем, когда конструктор готов создать новый объект .
Другой параметр, с префиксом , обозначает префикс , который мы добавляем в методы построителя, ответственные за настройку свойств . Значение по умолчанию для этого параметра – “с” . Вот почему мы не указали ни один из этих параметров в примере.
Давайте рассмотрим простой модульный тест, который охватывает десериализацию объекта Person :
String json = "{\"name\":\"Frank\",\"age\":50}"; Person person = new ObjectMapper().readValue(json, Person.class); assertEquals("Frank", person.getName()); assertEquals(50, person.getAge().intValue());
5. Заключение
В этой короткой статье мы рассмотрели, как десериализовать неизменяемые объекты с помощью библиотеки Джексона.
Весь код, связанный с этой статьей, можно найти на GitHub .