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

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Gson: основы сериализации и десериализации

1. Что такое Gson и зачем он нужен

Gson — это библиотека от Google для работы с JSON в Java.

Она позволяет:
Преобразовывать Java-объекты в JSON (сериализация).
Восстанавливать Java-объекты из JSON (десериализация).


Почему Gson?
Простота: минимум кода для работы.
Мощность: поддержка сложных структур (коллекции, вложенные объекты, generics).
Нет зависимостей: работает без дополнительных библиотек.


Пример JSON и его Java-представление

Допустим, у нас есть JSON:
{
"name": "John",
"age": 30,
"isDeveloper": true
}


Ему соответствует Java-класс:
public class Person {
private String name;
private int age;
private boolean isDeveloper;

// Конструктор, геттеры и сеттеры (обязательны для корректной работы)
public Person(String name, int age, boolean isDeveloper) {
this.name = name;
this.age = age;
this.isDeveloper = isDeveloper;
}

// Геттеры и сеттеры (опущены для краткости, но должны быть)
}


Подключение Gson

Через Maven (добавить в pom.xml):

<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version> <!-- Актуальная версия на момент 2025 года -->
</dependency>


Через Gradle (добавить в build.gradle):
implementation 'com.google.code.gson:gson:2.10.1'



2. Простая сериализация Java-объекта в JSON


Создание POJO

POJO (Plain Old Java Object) — простой Java-класс с полями, конструктором и геттерами/сеттерами.

Пример:
public class Book {
private String title;
private String author;
private double price;

public Book(String title, String author, double price) {
this.title = title;
this.author = author;
this.price = price;
}

// Геттеры (обязательны для сериализации)
public String getTitle() { return title; }
public String getAuthor() { return author; }
public double getPrice() { return price; }
}


Сериализация с помощью Gson.toJson()

Создаем объект Gson:
Gson gson = new Gson();


Сериализуем объект в JSON-строку:
Book book = new Book("Clean Code", "Robert Martin", 29.99);
String json = gson.toJson(book);


Выводим результат:

System.out.println(json);


Результат:
{"title":"Clean Code","author":"Robert Martin","price":29.99}


Как это работает?

Gson рефлективно анализирует поля класса.
Имена полей становятся ключами JSON.
Примитивы (int, boolean), строки (String) и числа с плавающей точкой (double) преобразуются в соответствующие JSON-типы.


Полный пример кода
import com.google.gson.Gson;

public class Main {
public static void main(String[] args) {
// Создаем объект
Book book = new Book("Clean Code", "Robert Martin", 29.99);

// Сериализуем в JSON
Gson gson = new Gson();
String json = gson.toJson(book);

// Выводим JSON
System.out.println(json);
}
}


Вывод:
{"title":"Clean Code","author":"Robert Martin","price":29.99}


Важные замечания

Поля должны быть private (или иметь геттеры).
Поля со значением null не включаются в JSON (если не настроено иначе).
Gson автоматически обрабатывает вложенные объекты и коллекции.

#Java #middle #Gson
Базовая десериализация и аннотации в Gson

Десериализация JSON в Java-объект


Метод fromJson(String, Class<T>)
Десериализация — процесс преобразования JSON-строки в Java-объект. Основной метод:

Gson gson = new Gson();
MyClass obj = gson.fromJson(jsonString, MyClass.class);


Пример
Допустим, есть JSON:
{
"model": "Tesla Model S",
"year": 2023,
"electric": true
}


Соответствующий Java-класс:
public class Car {
private String model;
private int year;
private boolean electric;

// Обязателен конструктор по умолчанию (или @SerializedConstructor в новых версиях)
public Car() {}

// Геттеры и сеттеры
public String getModel() { return model; }
public int getYear() { return year; }
public boolean isElectric() { return electric; }
}


Десериализация:
String json = "{\"model\":\"Tesla Model S\",\"year\":2023,\"electric\":true}";
Gson gson = new Gson();
Car car = gson.fromJson(json, Car.class);

System.out.println(car.getModel()); // Tesla Model S


Обработка ошибок

Gson выбрасывает JsonSyntaxException при невалидном JSON:
try {
Car car = gson.fromJson("{invalid json}", Car.class);
} catch (JsonSyntaxException e) {
System.err.println("Ошибка парсинга JSON: " + e.getMessage());
}


Аннотации @SerializedName и @Expose

@SerializedName — для нестандартных ключей JSON

Если имя поля в Java не совпадает с ключом в JSON:
public class User {
@SerializedName("user_name")
private String name; // Сопоставляется с JSON-ключом "user_name"

@SerializedName(value = "user_age", alternate = {"age", "years"})
private int age; // Допустимые альтернативные ключи в JSON
}


Пример JSON:
{"user_name": "Alice", "age": 25}


@Expose — избирательная сериализация/десериализация

Поля без @Expose игнорируются. Требуется особый Gson:
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();


Пример класса:
public class Product {
@Expose
private String name; // Сериализуется и десериализуется

@Expose(serialize = false)
private int id; // Только десериализация (из JSON в Java)

private String secret; // Игнорируется полностью
}


Отличие от Jackson

Аннотации:

В Gson: @SerializedName@JsonProperty в Jackson.
@Expose → Аналог @JsonInclude + @JsonIgnore.

Подход:
Gson использует рефлексию по умолчанию, Jackson — аннотации.

Производительность:
Jackson быстрее в некоторых сценариях, но Gson проще в настройке.

Полный пример

import com.google.gson.*;
import com.google.gson.annotations.*;

public class Main {
static class Device {
@SerializedName("device_name")
@Expose
private String name;

@Expose(deserialize = false)
private String manufacturer;

public Device(String name, String manufacturer) {
this.name = name;
this.manufacturer = manufacturer;
}
}

public static void main(String[] args) {
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.setPrettyPrinting()
.create();

// Сериализация (manufacturer исключен, т.к. deserialize = false)
Device device = new Device("Phone", "BrandX");
String json = gson.toJson(device);
System.out.println(json);

// Десериализация
String inputJson = "{\"device_name\":\"Tablet\",\"manufacturer\":\"BrandY\"}";
Device parsed = gson.fromJson(inputJson, Device.class);
System.out.println(parsed.name); // "Tablet"
}
}


Вывод:
{
"device_name": "Phone"
}


Ключевые моменты

@SerializedName решает проблему различий в именах JSON/Java.
@Expose дает контроль над процессами сериализации/десериализации.
Для работы
@Expose требуется GsonBuilder.

#Java #middle #Gson #SerializedName #Expose
Работа с коллекциями, вложенными объектами и generic-типами в Gson

1. Работа с коллекциями

Сериализация/десериализация списков (List<T>)
Пример с List<String>:

Gson gson = new Gson();

// Сериализация списка в JSON
List<String> languages = Arrays.asList("Java", "Kotlin", "Python");
String json = gson.toJson(languages);
System.out.println(json); // ["Java","Kotlin","Python"]

// Десериализация JSON обратно в List
List<String> parsedList = gson.fromJson(json, List.class);
System.out.println(parsedList.get(0)); // Java


Проблема: При использовании List.class тип элементов стирается. Для generic-типов нужен TypeToken.

Использование TypeToken для generic-типов
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;

// Создаем Type для List<String>
Type listType = new TypeToken<List<String>>() {}.getType();

// Десериализация с сохранением типа
String json = "[\"Apple\", \"Banana\"]";
List<String> fruits = gson.fromJson(json, listType);
System.out.println(fruits.get(0).toUpperCase()); // APPLE (без TypeToken был бы Object!)


Пример с массивами

// Сериализация массива
int[] numbers = {1, 2, 3};
String numbersJson = gson.toJson(numbers);
System.out.println(numbersJson); // [1,2,3]

// Десериализация обратно в массив
int[] parsedNumbers = gson.fromJson(numbersJson, int[].class);
System.out.println(parsedNumbers[0]); // 1


Работа с Map<String, Object>

// Сериализация Map
Map<String, Object> data = new HashMap<>();
data.put("name", "John");
data.put("age", 30);
data.put("skills", Arrays.asList("Java", "SQL"));

String mapJson = gson.toJson(data);
System.out.println(mapJson);
// {"skills":["Java","SQL"],"name":"John","age":30}

// Десериализация Map
Type mapType = new TypeToken<Map<String, Object>>() {}.getType();
Map<String, Object> parsedMap = gson.fromJson(mapJson, mapType);
System.out.println(parsedMap.get("name")); // John


2. Вложенные объекты и сложные структуры

Объекты внутри объектов
Пример JSON с вложенностью:

{
"name": "Alice",
"address": {
"city": "New York",
"street": "5th Avenue"
}
}


Соответствующие Java-классы:
class Address {
private String city;
private String street;

// Конструктор, геттеры и сеттеры
public Address(String city, String street) {
this.city = city;
this.street = street;
}

public String getCity() { return city; }
public String getStreet() { return street; }
}

class Person {
private String name;
private Address address;

// Конструктор, геттеры и сеттеры
}


Десериализация вложенного объекта
String personJson = """
{
"name": "Alice",
"address": {
"city": "New York",
"street": "5th Avenue"
}
}
""";

Gson gson = new Gson();
Person person = gson.fromJson(personJson, Person.class);

System.out.println(person.getName()); // Alice
System.out.println(person.getAddress().getCity()); // New York


Сериализация сложного объекта
Address address = new Address("Berlin", "Main Street");
Person person = new Person("Bob", address);

String json = gson.toJson(person);
System.out.println(json);
// {"name":"Bob","address":{"city":"Berlin","street":"Main Street"}}


Как обрабатываются вложенности
Gson рекурсивно обходит все поля объекта.
Для каждого вложенного объекта создается новый экземпляр.
Поддерживается любая глубина вложенности.


Пример с коллекцией вложенных объектов

JSON:
{
"team": "Developers",
"members": [
{
"name": "John",
"role": "Backend"
},
{
"name": "Anna",
"role": "Frontend"
}
]
}


Java-классы:
class TeamMember {
private String name;
private String role;
// конструктор и геттеры
}

class Team {
private String teamName;
private List<TeamMember> members;
// конструктор и геттеры
}


Десериализация:
Type teamType = new TypeToken<Team>() {}.getType();
Team team = gson.fromJson(jsonString, teamType);


#Java #middle #Gson
Кастомизация и адаптеры в Gson

1. Кастомные сериализаторы и десериализаторы

Gson позволяет переопределять стандартное поведение сериализации и десериализации с помощью интерфейсов JsonSerializer<T> и JsonDeserializer<T>.

1.1. Создание кастомного сериализатора (JsonSerializer<T>)
Используется, когда нужно изменить стандартное преобразование объекта в JSON.

Пример: Сериализация объекта User с особым форматированием поля email.
public class User {
private String name;
private String email;

// Конструкторы, геттеры и сеттеры
}

public class UserSerializer implements JsonSerializer<User> {
@Override
public JsonElement serialize(User user, Type typeOfSrc, JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("name", user.getName());
jsonObject.addProperty("email", user.getEmail().toLowerCase()); // Приводим email к нижнему регистру
return jsonObject;
}
}


1.2. Создание кастомного десериализатора (JsonDeserializer<T>)
Используется, когда нужно изменить стандартное преобразование JSON в объект.

Пример: Десериализация JSON с дополнительной валидацией email.


public class UserDeserializer implements JsonDeserializer<User> {
@Override
public User deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
String name = jsonObject.get("name").getAsString();
String email = jsonObject.get("email").getAsString();

if (!email.contains("@")) {
throw new JsonParseException("Invalid email format");
}

return new User(name, email);
}
}


1.3. Регистрация адаптеров через GsonBuilder
Чтобы применить кастомные сериализаторы и десериализаторы, их нужно зарегистрировать в GsonBuilder:

Gson gson = new GsonBuilder()
.registerTypeAdapter(User.class, new UserSerializer()) // Сериализатор
.registerTypeAdapter(User.class, new UserDeserializer()) // Десериализатор
.create();

// Сериализация
User user = new User("John", "John@Example.com");
String json = gson.toJson(user); // {"name":"John","email":"john@example.com"}

// Десериализация
User parsedUser = gson.fromJson(json, User.class);


1.4. Пример: Кастомный формат даты
Если стандартный формат даты (Date) не подходит, можно задать свой:

public class DateSerializer implements JsonSerializer<Date> {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");

@Override
public JsonElement serialize(Date date, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(dateFormat.format(date));
}
}

Gson gson = new GsonBuilder()
.registerTypeAdapter(Date.class, new DateSerializer())
.create();

Date now = new Date();
String json = gson.toJson(now); // "12.05.2025"


#Java #middle #Gson #JsonSerializer #JsonDeserializer
2. Настройка Gson через GsonBuilder

GsonBuilder позволяет гибко настраивать поведение Gson.

2.1. Основные методы настройки
.setPrettyPrinting(): Форматирует JSON с отступами для читаемости
.serializeNulls(): Сериализует поля со значением null (по умолчанию они пропускаются)
.excludeFieldsWithoutExposeAnnotation(): Игнорирует поля без аннотации
@Expose

Пример:
Gson gson = new GsonBuilder()
.setPrettyPrinting() // Красивый вывод JSON
.serializeNulls() // Включает null-поля
.excludeFieldsWithoutExposeAnnotation() // Только помеченные @Expose
.create();


2.2. Использование @Expose для выборочной сериализации
Поля без @Expose игнорируются, если включена соответствующая настройка.

public class User {
@Expose
private String name; // Будет сериализовано

private String password; // Не будет сериализовано
}

Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();

User user = new User("John", "secret");
String json = gson.toJson(user); // {"name":"John"}


2.3. Полный пример кастомной конфигурации
Gson
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.serializeNulls()
.setDateFormat("dd.MM.yyyy") // Формат даты по умолчанию
.registerTypeAdapter(User.class, new UserSerializer())
.excludeFieldsWithoutExposeAnnotation()
.create();


#Java #middle #Gson #GsonBuilder
Работа с JsonElement и полезные советы в Gson

JsonElement, JsonObject, JsonArray — работа с JSON вручную

Библиотека Gson предоставляет классы JsonElement, JsonObject и JsonArray для ручного разбора и модификации JSON.

Основные классы:
JsonElement — базовый абстрактный класс, представляющий любой элемент JSON (объект, массив, примитив).
JsonObject — подкласс JsonElement, представляющий JSON-объект ({ ... }).
JsonArray — подкласс JsonElement, представляющий JSON-массив ([ ... ]).


Пример разбора JSON вручную:
import com.google.gson.*;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;

public class ManualJsonParsing {
public static void main(String[] args) {
String json = """
{
"name": "John",
"age": 30,
"skills": ["Java", "Kotlin"],
"address": {
"city": "New York",
"zip": "10001"
}
}
""";

JsonElement rootElement = JsonParser.parseString(json);

// Проверяем, что корневой элемент — JsonObject
if (rootElement.isJsonObject()) {
JsonObject rootObject = rootElement.getAsJsonObject();

// Доступ к примитивным полям
String name = rootObject.get("name").getAsString();
int age = rootObject.get("age").getAsInt();

System.out.println("Name: " + name);
System.out.println("Age: " + age);

// Доступ к массиву
JsonArray skills = rootObject.get("skills").getAsJsonArray();
System.out.println("Skills:");
for (JsonElement skill : skills) {
System.out.println("- " + skill.getAsString());
}

// Доступ к вложенному объекту
JsonObject address = rootObject.get("address").getAsJsonObject();
String city = address.get("city").getAsString();
String zip = address.get("zip").getAsString();

System.out.println("City: " + city);
System.out.println("Zip: " + zip);
}
}
}


Когда не знаешь точную структуру JSON

Если структура JSON может меняться, можно проверять наличие полей и их типы:
JsonObject userObject = rootElement.getAsJsonObject();

// Проверка наличия поля
if (userObject.has("email")) {
String email = userObject.get("email").getAsString();
System.out.println("Email: " + email);
} else {
System.out.println("Email not provided");
}

// Проверка типа поля
JsonElement ageElement = userObject.get("age");
if (ageElement != null && !ageElement.isJsonNull()) {
if (ageElement.isJsonPrimitive() && ageElement.getAsJsonPrimitive().isNumber()) {
int age = ageElement.getAsInt();
System.out.println("Age: " + age);
} else {
System.out.println("Age is not a number");
}
}


Добавление и изменение значений вручную

JsonObject user = new JsonObject();
user.addProperty("name", "Alice"); // Добавление строки
user.addProperty("age", 25); // Добавление числа
user.addProperty("isActive", true); // Добавление булева значения

// Добавление массива
JsonArray languages = new JsonArray();
languages.add("Java");
languages.add("Python");
user.add("languages", languages);

// Добавление вложенного объекта
JsonObject address = new JsonObject();
address.addProperty("city", "London");
address.addProperty("country", "UK");
user.add("address", address);

user.addProperty("age", 26); // Перезаписываем age

System.out.println(new Gson().toJson(user));


Преобразование между JsonElement и Java-объектами

Использование fromJson и toJsonTree

Из JSON в POJO (fromJson)
Gson gson = new Gson();
String json = "{\"name\":\"Bob\",\"age\":40}";

// Прямое преобразование строки в объект
Person person = gson.fromJson(json, Person.class);
System.out.println(person.getName()); // Bob

// Если есть JsonElement, можно использовать его
JsonElement jsonElement = JsonParser.parseString(json);
Person personFromElement = gson.fromJson(jsonElement, Person.class);


#Java #middle #Gson #JsonElement #JsonObject #JsonArray
Преобразование между JsonElement и Java-объектами

Использование fromJson и toJsonTree

Из JSON в POJO (fromJson)
Gson gson = new Gson();
String json = "{\"name\":\"Bob\",\"age\":40}";

// Прямое преобразование строки в объект
Person person = gson.fromJson(json, Person.class);
System.out.println(person.getName()); // Bob

// Если есть JsonElement, можно использовать его
JsonElement jsonElement = JsonParser.parseString(json);
Person personFromElement = gson.fromJson(jsonElement, Person.class);


Из POJO в JsonElement (toJsonTree)

Person person = new Person("Bob", 40);
JsonElement personElement = gson.toJsonTree(person);

// Теперь можно модифицировать JSON
if (personElement.isJsonObject()) {
JsonObject personObject = personElement.getAsJsonObject();
personObject.addProperty("email", "bob@example.com");
}

String modifiedJson = gson.toJson(personElement);
System.out.println(modifiedJson);


Как конвертировать JsonElement обратно в POJO
JsonObject userJson = new JsonObject();
userJson.addProperty("name", "Eve");
userJson.addProperty("age", 28);

// Преобразование JsonObject в POJO
Gson gson = new Gson();
Person person = gson.fromJson(userJson, Person.class);
System.out.println(person.getName()); // Eve


Полезные советы

Проверка isJsonNull() перед чтением значений
JsonElement element = jsonObject.get("optionalField");
if (element != null && !element.isJsonNull()) {
String value = element.getAsString();
}


Обработка разных типов полей
JsonElement dynamicField = jsonObject.get("dynamicField");
if (dynamicField.isJsonPrimitive()) {
JsonPrimitive primitive = dynamicField.getAsJsonPrimitive();
if (primitive.isString()) {
// Обработка строки
} else if (primitive.isNumber()) {
// Обработка числа
}
} else if (dynamicField.isJsonArray()) {
// Обработка массива
}


Использование JsonParser для разбора строки

JsonElement parsed = JsonParser.parseString(jsonString);


Создание сложных JSON структур
JsonObject response = new JsonObject();
JsonArray items = new JsonArray();

JsonObject item1 = new JsonObject();
item1.addProperty("id", 1);
item1.addProperty("name", "Item 1");

items.add(item1);
response.add("items", items);
response.addProperty("count", 1);

String jsonOutput = gson.toJson(response);


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

#Java #middle #Gson #JsonElement #JsonObject #JsonArray