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
Что выведет код?

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
Варианты ответа:
Anonymous Quiz
29%
2 1
19%
3 1
35%
2 3
16%
3 3
Не, ну а че, на кулачках решать какой фреймворк лучше - вариант? 🥴 💪 😄

https://t.me/Java_for_beginner_dev

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

Аннотации 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
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
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
Что выведет код?

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
Варианты ответа:
Anonymous Quiz
10%
A A
50%
C A
23%
C B
17%
B A
Потому что в конец обленимся 😁

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