Java for Beginner
672 subscribers
541 photos
155 videos
12 files
827 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Потому что в конец обленимся 😁

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
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
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Channel photo updated
Jackson

Глобальная настройка ObjectMapper: как управлять сериализацией и десериализацией

Jackson предоставляет удобный способ централизованно настраивать поведение через ObjectMapper. Эта конфигурация позволяет управлять форматированием JSON, обработкой неизвестных полей, null-значений и множеством других аспектов.

Инициализация ObjectMapper
import com.fasterxml.jackson.databind.ObjectMapper;

ObjectMapper mapper = new ObjectMapper();
Можно использовать его напрямую или создать бин (например, в Spring).


1. Игнорирование неизвестных полей

По умолчанию Jackson выбросит исключение, если в JSON попадётся поле, которого нет в Java-классе.

Это можно отключить так:
import com.fasterxml.jackson.databind.DeserializationFeature;

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);


Теперь лишние поля будут просто игнорироваться:
{
"name": "Alice",
"age": 30,
"extra_field": "ignored"
}


2. Красивая печать JSON (Pretty Print)

По умолчанию JSON сериализуется в одну строку. Чтобы включить форматирование с отступами:

import com.fasterxml.jackson.databind.SerializationFeature;

mapper.enable(SerializationFeature.INDENT_OUTPUT);


Пример вывода:

{
"name" : "Alice",
"age" : 30
}
Это особенно полезно для логирования и отладки.


3. Исключение null-полей

Если нужно убрать из JSON все поля с null, можно настроить так:
import com.fasterxml.jackson.annotation.JsonInclude;

mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);


Пример:
public class User {
public String name;
public String email; // может быть null
}


Результат без email, если он null:
{
"name": "Alice"
}


4. Ошибка при отсутствии обязательных полей

По умолчанию Jackson пропускает отсутствующие поля. Но можно требовать их наличия:
mapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, true);
mapper.configure(DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES, true);


5. Написание чисел как строки

mapper.configure(SerializationFeature.WRITE_NUMBERS_AS_STRINGS, true);


Результат:
{
"age": "30"
}


6. Установка глобального формата дат
import java.text.SimpleDateFormat;

mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));


Когда это полезно
— В проектах с нестабильными API
— При интеграции с фронтендом, где важно форматирование
— При логировании JSON в читаемом виде
— Для обеспечения устойчивости к изменяющимся данным


#Java #Training #Medium #Jackson #ObjectMapper
Что выведет код?

import java.util.*;

public class Task070525 {
public static void main(String[] args) {
TreeMap<Integer, String> tree = new TreeMap<>();
tree.put(1, "Java");
tree.put(1, "Python");
tree.put(2, "C++");
tree.put(3, "Go");
tree.remove(2);

System.out.println(tree.subMap(1, true, 3, true).values());
}
}


#Tasks
ИИ сделало бы все быстрее ☝️

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Jackson

Использование модулей в Jackson: JavaTimeModule и работа с Java 8 датами

Начиная с Java 8, в язык была добавлена новая мощная модель работы со временем: LocalDate, LocalDateTime, Instant и другие типы из пакета java.time. Однако стандартная конфигурация Jackson не умеет корректно сериализовать и десериализовать эти типы "из коробки".

Проблема по умолчанию

Если попытаться сериализовать объект с полем LocalDateTime, Jackson выдаст ошибку или выведет нечитабельное представление (например, через timestamp).

Пример:
public class Event {
public String name;
public LocalDateTime dateTime;

public Event() {}
public Event(String name, LocalDateTime dateTime) {
this.name = name;
this.dateTime = dateTime;
}
}


Event event = new Event("Conference", LocalDateTime.now());
String json = objectMapper.writeValueAsString(event);
Без дополнительных модулей Jackson не поймёт, как сериализовать LocalDateTime.


Решение: JavaTimeModule

Чтобы Jackson начал понимать java.time.*, нужно подключить модуль JavaTimeModule.

Подключение (если используешь Maven):
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>


Регистрация модуля:
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());


Важно: если хочешь сериализовать даты в человекочитаемом формате, отключи запись timestamp:
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);


Пример работы
Event event = new Event("Conference", LocalDateTime.of(2025, 4, 29, 10, 30));
String json = mapper.writeValueAsString(event);
System.out.println(json);


Результат:
{
"name": "Conference",
"dateTime": "2025-04-29T10:30:00"
}


Аналогично работает и с другими типами:
LocalDate
LocalTime
ZonedDateTime
Instant


Десериализация обратно
String input = "{\"name\":\"Conference\",\"dateTime\":\"2025-04-29T10:30:00\"}";
Event event = mapper.readValue(input, Event.class);


Другие полезные модули Jackson

ParameterNamesModule — помогает при десериализации через конструкторы без @JsonProperty
Jdk8Module — поддержка Optional, OptionalInt и других типов из java.util
AfterburnerModule — ускоряет работу Jackson на больших объёмах данных


#Java #Training #Medium #Jackson
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Jackson

Частичная сериализация с помощью @JsonView

Иногда возникает задача сериализовать один и тот же объект по-разному — в зависимости от ситуации, роли пользователя, уровня доступа или цели запроса. Например, показывать часть полей для публичного API и все — для администратора.

Jackson решает эту задачу с помощью механизма JSON Views.

Что такое JSON Views

@JsonView — это аннотация, позволяющая управлять, какие поля объекта попадут в JSON в зависимости от выбранного представления (view-класса).
Это как "фильтр по уровням доступа", встроенный прямо в сериализацию.

Шаг 1. Определяем уровни видимости (view)
public class Views {
public static class Public {}
public static class Internal extends Public {}
}
Можно создавать любые уровни — главное, чтобы они наследовались при необходимости.


Шаг 2. Аннотируем поля модели
import com.fasterxml.jackson.annotation.JsonView;

public class User {
@JsonView(Views.Public.class)
private String username;

@JsonView(Views.Internal.class)
private String email;

@JsonView(Views.Internal.class)
private String role;

public User() {}

public User(String username, String email, String role) {
this.username = username;
this.email = email;
this.role = role;
}

// Геттеры и сеттеры
}


Теперь:
username виден всем (включая Public)
email и role — только для Internal



Шаг 3. Сериализация с учетом view

ObjectMapper mapper = new ObjectMapper();

User user = new User("alice", "alice@example.com", "ADMIN");

// Публичный вид
String publicJson = mapper
.writerWithView(Views.Public.class)
.writeValueAsString(user);

System.out.println(publicJson);


Результат:

{
"username": "alice"
}


Если сериализовать с Internal view:

String internalJson = mapper
.writerWithView(Views.Internal.class)
.writeValueAsString(user);


Результат:
{
"username": "alice",
"email": "alice@example.com",
"role": "ADMIN"
}


Применение в REST (например, Spring)

В Spring можно использовать @JsonView прямо в контроллере:
@GetMapping("/user/public")
@JsonView(Views.Public.class)
public User getPublicUser() {
return userService.getCurrentUser();
}

@GetMapping("/user/internal")
@JsonView(Views.Internal.class)
public User getInternalUser() {
return userService.getCurrentUser();
}


Когда это нужно

Публичный/приватный API
Разные роли пользователей (гость, клиент, админ)
Безопасность: не передавать чувствительные поля
Удобство: не создавать множество DTO для каждой ситуации


#Java #Training #Medium #Jackson #JsonView
Что выведет код?

public class Task080525 {
public static void main(String[] args) {
int count = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i == j) continue;
count++;
}
}
System.out.println(count);
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
27%
3
42%
6
19%
9
12%
0
Анонс нового сериала на Netflix ✌️😂

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM