Jackson
Ключевые аннотации для сериализации.
Jackson предоставляет богатый набор аннотаций для управления тем, как Java-объекты сериализуются в JSON. На практике чаще всего используются три основные аннотации: @JsonProperty, @JsonIgnore и @JsonInclude.
@JsonProperty
Аннотация @JsonProperty позволяет задать имя поля в итоговом JSON независимо от имени переменной в Java-классе. Это особенно полезно, если требуется соблюдать определенные соглашения об именовании в JSON (например, использовать snake_case).
Пример:
При сериализации объект будет выглядеть так:
@JsonIgnore
Аннотация @JsonIgnore используется для исключения полей из сериализации и десериализации. Если поле не должно попадать в JSON-вывод или не должно учитываться при чтении JSON, достаточно добавить эту аннотацию.
Пример:
Результат сериализации:
@JsonInclude
Аннотация @JsonInclude позволяет управлять включением полей в JSON в зависимости от их значения. Например, можно настроить сериализацию так, чтобы поля с null не попадали в итоговый JSON.
Пример:
Если email будет null, результат сериализации будет таким:
#Java #Training #Medium #Jackson #JsonProperty #JsonIgnore #JsonInclude
Ключевые аннотации для сериализации.
Jackson предоставляет богатый набор аннотаций для управления тем, как Java-объекты сериализуются в JSON. На практике чаще всего используются три основные аннотации: @JsonProperty, @JsonIgnore и @JsonInclude.
@JsonProperty
Аннотация @JsonProperty позволяет задать имя поля в итоговом JSON независимо от имени переменной в Java-классе. Это особенно полезно, если требуется соблюдать определенные соглашения об именовании в JSON (например, использовать snake_case).
Пример:
import com.fasterxml.jackson.annotation.JsonProperty;
public class User {
@JsonProperty("user_name")
private String name;
private int age;
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
// Геттеры и сеттеры
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
При сериализации объект будет выглядеть так:
{"user_name":"Alice","age":25}
Без @JsonProperty имя поля в JSON было бы "name", но аннотация позволила задать собственное имя.
@JsonIgnore
Аннотация @JsonIgnore используется для исключения полей из сериализации и десериализации. Если поле не должно попадать в JSON-вывод или не должно учитываться при чтении JSON, достаточно добавить эту аннотацию.
Пример:
import com.fasterxml.jackson.annotation.JsonIgnore;
public class User {
private String name;
@JsonIgnore
private String password;
public User() {}
public User(String name, String password) {
this.name = name;
this.password = password;
}
// Геттеры и сеттеры
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Результат сериализации:
{"name":"Alice"}
Поле password полностью исключено из JSON.
@JsonInclude
Аннотация @JsonInclude позволяет управлять включением полей в JSON в зависимости от их значения. Например, можно настроить сериализацию так, чтобы поля с null не попадали в итоговый JSON.
Пример:
import com.fasterxml.jackson.annotation.JsonInclude;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
private String name;
private String email;
public User() {}
public User(String name, String email) {
this.name = name;
this.email = email;
}
// Геттеры и сеттеры
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Если email будет null, результат сериализации будет таким:
{"name":"Alice"}
Без @JsonInclude поле email также попало бы в JSON с null значением.
#Java #Training #Medium #Jackson #JsonProperty #JsonIgnore #JsonInclude
Что выведет код?
#Tasks
import java.util.*;
public class Task050525 {
public static void main(String[] args) {
TreeMap<String, Integer> tree = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
tree.put("Apple", 1);
tree.put("banana", 2);
tree.put("APPLE", 3);
System.out.println(tree.size() + " " + tree.get("aPpLe"));
}
}
#Tasks
Не, ну а че, на кулачках решать какой фреймворк лучше - вариант? 🥴 💪 😄
https://t.me/Java_for_beginner_dev
#Mems
https://t.me/Java_for_beginner_dev
#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопросы с собеседования 👩💻
Что такое аннотация в Java?
Что такое аннотация в Java?
Anonymous Quiz
7%
Комментарий в коде
89%
Метаданные для классов, методов или полей
0%
Оператор для циклов
4%
Тип данных
Jackson
Аннотации Jackson для десериализации и изменения структуры JSON
Иногда структура входящего JSON не совпадает напрямую с полями Java-объекта. Для корректной десериализации в таких случаях Jackson предлагает ряд аннотаций, среди которых особенно важны @JsonCreator, @JsonSetter и @JsonAlias.
@JsonCreator
Аннотация @JsonCreator позволяет указать, какой именно конструктор или фабричный метод должен использоваться для создания объекта из JSON.
Особенно полезна в случаях, когда объект должен быть создан через специфический конструктор, а не через пустой и геттеры/сеттеры.
Пример:
При десериализации Jackson использует указанный конструктор, а не требует пустой конструктор и сеттеры:
@JsonSetter
Аннотация @JsonSetter указывается на методе и сообщает Jackson, что данный метод должен использоваться для установки значения при десериализации.
Это полезно, когда метод сеттера отличается по названию от поля или нужно выполнить какую-то дополнительную обработку значения.
Пример:
JSON:
@JsonAlias
Аннотация @JsonAlias позволяет указывать альтернативные имена полей, которые могут приходить в JSON. Это особенно полезно для работы с нестабильными или изменяющимися API.
Пример:
Теперь следующий JSON будет корректно обработан:
или
Пример нестандартного маппинга
Иногда API может менять структуру данных или использовать разные названия для одного и того же поля. Комбинируя @JsonCreator, @JsonProperty и @JsonAlias, можно добиться правильной обработки даже самых нестандартных случаев.
Например:
#Java #Training #Medium #Jackson #JsonCreator #JsonSetter #JsonAlias
Аннотации Jackson для десериализации и изменения структуры JSON
Иногда структура входящего JSON не совпадает напрямую с полями Java-объекта. Для корректной десериализации в таких случаях Jackson предлагает ряд аннотаций, среди которых особенно важны @JsonCreator, @JsonSetter и @JsonAlias.
@JsonCreator
Аннотация @JsonCreator позволяет указать, какой именно конструктор или фабричный метод должен использоваться для создания объекта из JSON.
Особенно полезна в случаях, когда объект должен быть создан через специфический конструктор, а не через пустой и геттеры/сеттеры.
Пример:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class User {
private final String name;
private final int age;
@JsonCreator
public User(@JsonProperty("name") String name,
@JsonProperty("age") int age) {
this.name = name;
this.age = age;
}
// Только геттеры
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
При десериализации Jackson использует указанный конструктор, а не требует пустой конструктор и сеттеры:
String json = "{\"name\":\"Alice\",\"age\":30}";
User user = objectMapper.readValue(json, User.class);
@JsonSetter
Аннотация @JsonSetter указывается на методе и сообщает Jackson, что данный метод должен использоваться для установки значения при десериализации.
Это полезно, когда метод сеттера отличается по названию от поля или нужно выполнить какую-то дополнительную обработку значения.
Пример:
import com.fasterxml.jackson.annotation.JsonSetter;
public class Product {
private String name;
public Product() {}
public String getName() {
return name;
}
@JsonSetter("product_name")
public void setName(String name) {
this.name = name.toUpperCase();
}
}
JSON:
{
"product_name": "laptop"
}
При десериализации будет вызван метод setName, а имя продукта будет автоматически приведено к верхнему регистру: "LAPTOP".
@JsonAlias
Аннотация @JsonAlias позволяет указывать альтернативные имена полей, которые могут приходить в JSON. Это особенно полезно для работы с нестабильными или изменяющимися API.
Пример:
import com.fasterxml.jackson.annotation.JsonAlias;
public class Customer {
@JsonAlias({"user_name", "login"})
private String username;
public Customer() {}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
Теперь следующий JSON будет корректно обработан:
{ "user_name": "admin" }
или
{ "login": "admin" }
И в обоих случаях значение попадет в поле username.
Пример нестандартного маппинга
Иногда API может менять структуру данных или использовать разные названия для одного и того же поля. Комбинируя @JsonCreator, @JsonProperty и @JsonAlias, можно добиться правильной обработки даже самых нестандартных случаев.
Например:
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonAlias;
public class Employee {
private final String id;
private final String fullName;
@JsonCreator
public Employee(@JsonProperty("id") String id,
@JsonProperty("full_name") @JsonAlias({"name", "fullname"}) String fullName) {
this.id = id;
this.fullName = fullName;
}
public String getId() {
return id;
}
public String getFullName() {
return fullName;
}
}
Теперь Jackson корректно обработает JSON, где имя сотрудника приходит под разными ключами: full_name, name или fullname.
#Java #Training #Medium #Jackson #JsonCreator #JsonSetter #JsonAlias
Jackson
Работа со списками, картами и вложенными объектами
JSON — это не только простые объекты, но и сложные структуры: списки, словари, вложенные объекты. В этом посте разберем, как Jackson справляется с такими случаями, и как правильно сериализовать и десериализовать коллекции и составные структуры.
Списки объектов
Представим, что у нас есть список пользователей:
Сериализация списка в JSON:
Результат:
Десериализация списка обратно в Java:
Карты (мапы)
JSON-объект с произвольными ключами часто удобно мапить в Map<String, Object>.
Например:
Можно прочитать в Map:
Сериализация карты обратно:
Вложенные объекты
Вложенные структуры — это JSON, где одно поле содержит объект:
Соответствующий Java-класс:
Jackson автоматически корректно сериализует и десериализует такие вложенные объекты:
Результат:
И обратно:
Комбинирование структур
Jackson легко справляется с комбинацией вложенных объектов, списков и мап:
Нужно лишь правильно описать классы:
#Java #Training #Medium #Jackson
Работа со списками, картами и вложенными объектами
JSON — это не только простые объекты, но и сложные структуры: списки, словари, вложенные объекты. В этом посте разберем, как Jackson справляется с такими случаями, и как правильно сериализовать и десериализовать коллекции и составные структуры.
Списки объектов
Представим, что у нас есть список пользователей:
public class User {
private String name;
private int age;
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
// Геттеры и сеттеры
}
Сериализация списка в JSON:
List<User> users = List.of(
new User("Alice", 30),
new User("Bob", 25)
);
String json = objectMapper.writeValueAsString(users);
System.out.println(json);
Результат:
[
{"name":"Alice","age":30},
{"name":"Bob","age":25}
]
Десериализация списка обратно в Java:
String jsonInput = "[{\"name\":\"Alice\",\"age\":30},{\"name\":\"Bob\",\"age\":25}]";
List<User> users = objectMapper.readValue(
jsonInput,
new TypeReference<List<User>>() {}
);
Здесь важно использовать TypeReference, чтобы сохранить информацию о типе во время десериализации.
Карты (мапы)
JSON-объект с произвольными ключами часто удобно мапить в Map<String, Object>.
Например:
{
"name": "Alice",
"age": 30,
"active": true
}
Можно прочитать в Map:
String json = "{\"name\":\"Alice\",\"age\":30,\"active\":true}";
Map<String, Object> map = objectMapper.readValue(json, new TypeReference<Map<String, Object>>() {});
Сериализация карты обратно:
Map<String, Object> data = new HashMap<>();
data.put("name", "Alice");
data.put("age", 30);
data.put("active", true);
String jsonOutput = objectMapper.writeValueAsString(data);
Вложенные объекты
Вложенные структуры — это JSON, где одно поле содержит объект:
{
"id": 1,
"user": {
"name": "Alice",
"age": 30
}
}
Соответствующий Java-класс:
public class Wrapper {
private int id;
private User user;
public Wrapper() {}
public Wrapper(int id, User user) {
this.id = id;
this.user = user;
}
// Геттеры и сеттеры
}
Jackson автоматически корректно сериализует и десериализует такие вложенные объекты:
Wrapper wrapper = new Wrapper(1, new User("Alice", 30));
String json = objectMapper.writeValueAsString(wrapper);
Результат:
{
"id": 1,
"user": {
"name": "Alice",
"age": 30
}
}
И обратно:
String input = "{\"id\":1,\"user\":{\"name\":\"Alice\",\"age\":30}}";
Wrapper wrapper = objectMapper.readValue(input, Wrapper.class);
Комбинирование структур
Jackson легко справляется с комбинацией вложенных объектов, списков и мап:
{
"group": "admins",
"members": [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25}
],
"meta": {
"created": "2023-10-01",
"active": true
}
}
Нужно лишь правильно описать классы:
public class Group {
private String group;
private List<User> members;
private Map<String, Object> meta;
// Конструктор, геттеры, сеттеры
}
#Java #Training #Medium #Jackson
Что выведет код?
#Tasks
import java.util.*;
public class Task060525 {
public static void main(String[] args) {
TreeSet<String> tree = new TreeSet<>(Comparator.reverseOrder());
tree.add("B");
tree.add("A");
tree.add("C");
tree.add("A");
System.out.println(tree.pollFirst() + " " + tree.pollLast());
}
}
#Tasks
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопросы с собеседования 👩💻
Что такое module в Java?
Что такое module в Java?
Anonymous Quiz
8%
Класс для работы с файлами
88%
Единица модульной организации кода
0%
Тип данных для чисел
5%
Метод для обработки исключений
Jackson
Кастомные десериализаторы
Иногда структура входящего JSON или требования к обработке данных слишком специфичны, и стандартной десериализации Jackson оказывается недостаточно. В таких случаях можно реализовать собственный десериализатор, унаследовавшись от JsonDeserializer.
Когда нужен кастомный десериализатор
— Нужно преобразовать нестандартный формат данных
— Нужно добавить проверку, валидацию, нормализацию
— Нужно маппить одно поле в несколько
— Нужно логировать, фильтровать, трансформировать содержимое JSON
Шаг 1: Создание собственного десериализатора
Для этого создаем класс, расширяющий JsonDeserializer<T>:
Шаг 2: Привязка десериализатора к полю
Теперь мы можем использовать наш кастомный десериализатор на нужном поле через аннотацию @JsonDeserialize.
Шаг 3: Пример использования
Что ещё можно делать в кастомных десериализаторах
— Преобразовывать дату из нестандартного формата
— Разбирать строки с разделителями (например, CSV в List)
— Валидировать числовые диапазоны
— Преобразовывать строки в enum с логикой по умолчанию
— Обрабатывать null как спецзначения
— Инъектировать зависимости (через context.findInjectableValue())
#Java #Training #Medium #Jackson
Кастомные десериализаторы
Иногда структура входящего JSON или требования к обработке данных слишком специфичны, и стандартной десериализации Jackson оказывается недостаточно. В таких случаях можно реализовать собственный десериализатор, унаследовавшись от JsonDeserializer.
Когда нужен кастомный десериализатор
— Нужно преобразовать нестандартный формат данных
— Нужно добавить проверку, валидацию, нормализацию
— Нужно маппить одно поле в несколько
— Нужно логировать, фильтровать, трансформировать содержимое JSON
Шаг 1: Создание собственного десериализатора
Для этого создаем класс, расширяющий JsonDeserializer<T>:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
public class NameDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
String rawValue = p.getText();
if (rawValue == null || rawValue.trim().isEmpty()) {
throw new IOException("Имя не может быть пустым");
}
// Пример нормализации: первая буква заглавная
return rawValue.substring(0, 1).toUpperCase() + rawValue.substring(1).toLowerCase();
}
}
Шаг 2: Привязка десериализатора к полю
Теперь мы можем использовать наш кастомный десериализатор на нужном поле через аннотацию @JsonDeserialize.
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
public class User {
@JsonDeserialize(using = NameDeserializer.class)
private String name;
private int age;
public User() {}
// Геттеры и сеттеры
}
Шаг 3: Пример использования
String json = "{\"name\":\" aLiCe \", \"age\":30}";
User user = objectMapper.readValue(json, User.class);
System.out.println(user.getName()); // Выведет: Alice
Если в поле name будет пустая строка или только пробелы — Jackson выбросит исключение, как мы это настроили в десериализаторе.
Что ещё можно делать в кастомных десериализаторах
— Преобразовывать дату из нестандартного формата
— Разбирать строки с разделителями (например, CSV в List)
— Валидировать числовые диапазоны
— Преобразовывать строки в enum с логикой по умолчанию
— Обрабатывать null как спецзначения
— Инъектировать зависимости (через context.findInjectableValue())
#Java #Training #Medium #Jackson