Gson — бібліотека від Google для серіалізації Java-об'єктів у JSON і назад, широко використовувана в Android-розробці. Вона дозволяє перетворювати складні графи об'єктів у компактні JSON-рядки без ручного написання парсерів. За даними Google Gson, 2024, бібліотека налічує понад 23 тисячі зірок на GitHub і залишається одним із найпопулярніших рішень для роботи з JSON в екосистемі Java та Kotlin.
Головне
Gson — це Java-бібліотека, розроблена Google для перетворення об'єктів у JSON-представлення та назад. Вона використовує рефлексію для аналізу структури класів, що дозволяє працювати без попередньої конфігурації. Gson підтримує довільні Java-об'єкти, колекції, масиви, дженерики та вкладені класи. Бібліотека не потребує анотацій для базового використання, але надає їх для тонкого налаштування. Основний недолік рефлексії — зниження продуктивності під час ініціалізації та неможливість оптимізації на етапі компіляції, що особливо помітно на холодному старті Android-додатку при десеріалізації сотень моделей. Незважаючи на це, Gson залишається надійним вибором для більшості проєктів завдяки стабільності та обширній документації.
Gson був випущений Google у 2008 році та швидко став стандартом де-факто для JSON в Android-додатках. До появи Moshi та kotlinx.serialization Gson залишався єдиним популярним вибором для Kotlin-проєктів. Простота підключення — додавання однієї залежності в build.gradle — і відсутність обов'язкових анотацій зробили Gson популярним серед розробників будь-якого рівня.
// Підключення Gson в build.gradle
dependencies {
implementation 'com.google.code.gson:gson:2.10.1'
}
// Базове використання
data class User(
val id: Int,
val name: String,
val email: String
)
val gson = Gson()
val user = User(1, "John", "john@test.com")
val json = gson.toJson(user)
println(json) // {"id":1,"name":"John","email":"john@test.com"}
Окрім базової серіалізації, Gson надає GsonBuilder для налаштування поведінки: форматування дат, відключення екранування HTML, регістру ключів та користувацьких екземплярів. GsonBuilder також дозволяє реєструвати кастомні JsonSerializer та JsonDeserializer для типів, які бібліотека не може обробити автоматично. Гнучкість конфігурації робить GsonBuilder незамінним та корисним інструментом при адаптації бібліотеки під специфічні вимоги проєкту в сучасній Android-розробці.
toJson перетворює Java-об'єкт у JSON-рядок, аналізуючи його поля через рефлексію. За замовчуванням Gson включає всі поля, крім transient та static. Метод підтримує будь-які типи: примітиви, об'єкти, колекції та масиви. fromJson виконує зворотне перетворення, приймаючи JSON-рядок та клас цільового об'єкта, і повертає екземпляр із заповненими полями.
При серіалізації Gson рекурсивно обходить всі поля об'єкта, включаючи вкладені. Циклічні посилання призводять до StackOverflowError, тому їх потрібно виключати через анотацію @Expose або кастомний адаптер. Для колекцій Gson зберігає тип елементів, але при десеріалізації списку з дженериками потрібен TypeToken для збереження інформації про тип.
// data class із вкладеним об'єктом
data class Address(
val city: String,
val street: String
)
data class Employee(
val id: Int,
val name: String,
val address: Address
)
val gson = Gson()
val employee = Employee(1, "Alice",
Address("New York", "5th Ave"))
// Серіалізація в JSON
val json = gson.toJson(employee)
// Десеріалізація з JSON
val jsonString = """
{"id":2,"name":"Bob","address":{"city":"London","street":"Baker St"}}
"""
val parsed = gson.fromJson(jsonString, Employee::class.java)
Gson надає набір анотацій для керування процесом серіалізації. @SerializedName задає ім'я JSON-ключа, що відрізняється від імені поля. @Expose керує включенням поля в серіалізацію: Gson, створений через GsonBuilder.excludeFieldsWithoutExposeAnnotation(), буде обробляти лише поля з @Expose. @Since та @Until контролюють версійність полів.
Анотація @SerializedName вирішує проблему невідповідності імен: сервер може використовувати snake_case, а в коді прийнято camelCase. Анотація приймає значення та опціональні альтернативи для зворотної сумісності. @Expose дозволяє приховати чутливі поля (паролі, токени) від серіалізації, позначаючи їх як @Expose(serialize = false). Крім включення та виключення, @Expose можна комбінувати з GsonBuilder.excludeFieldsWithoutExposeAnnotation для створення білого списку полів, що допомагає контролювати поверхню атаки при серіалізації об'єктів з великою кількістю полів.
// Модель з анотаціями Gson
data class UserResponse(
@SerializedName("user_id")
val userId: Int,
@SerializedName("full_name",
alternate = [Alternative("name")])
val fullName: String,
@Expose(serialize = false)
val password: String
)
// Gson із фільтрацією @Expose
val gson = GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.setPrettyPrinting()
.create()
val user = UserResponse(1, "John", "secret123")
println(gson.toJson(user))
// {"user_id":1,"full_name":"John"} — пароль виключено
Проблема дженериків в Java та Kotlin полягає в стиранні типів під час компіляції. Коли Gson десеріалізує List<User>, він не знає тип елемента і повертає List<Map<String, Any>>. Для збереження інформації про тип Gson надає TypeToken — абстрактний клас, який захоплює параметр типу через анонімний клас. Без TypeToken розробнику довелося б вручну перетворювати кожен елемент із Map у цільовий тип, що призводить до громіздкого коду та втрати продуктивності.
TypeToken вирішує проблему стирання типів. Розробник створює анонімного спадкоємця TypeToken з потрібним параметром типу, і Gson використовує інформацію з сигнатури класу для коректної десеріалізації. TypeToken також працює з Map, Set та будь-якими іншими параметризованими типами, включаючи вкладені дженерики. Зокрема, для Map<String, List<User>> потрібен TypeToken з повною сигнатурою вкладеного типу, інакше Gson десеріалізує значення як List<Map<String, Any>> замість List<User>.
// TypeToken для десеріалізації списку
data class Product(
val id: Int,
val title: String,
val price: Double
)
val jsonArray = """
[
{"id":1,"title":"Phone","price":599.0},
{"id":2,"title":"Laptop","price":1299.0}
]
"""
val gson = Gson()
val listType = object : TypeToken<List<Product>>() {}
val products: List<Product> =
gson.fromJson(jsonArray, listType.type)
// Кастомний десеріалізатор
class LocalDateAdapter :
JsonDeserializer<LocalDate> {
override fun deserialize(
json: JsonElement,
typeOfT: java.lang.reflect.Type,
context: JsonDeserializationContext
): LocalDate {
return LocalDate.parse(json.asString)
}
}
Для кастомної логіки серіалізації Gson підтримує інтерфейси JsonSerializer та JsonDeserializer. Вони реєструються через GsonBuilder.registerTypeAdapter() і дозволяють обробляти типи, які бібліотека не може серіалізувати автоматично: дати Java 8, Enum з нестандартними значеннями або сторонні класи без доступу до вихідного коду. При реалізації адаптера важливо стежити за продуктивністю: виклик рефлексії всередині кастомного адаптера зводить нанівець переваги ручного керування, тому переважно використовувати прямі виклики методів і полів. В екосистемі Gson також існує модуль gson-extras, який надає адаптери для поширених типів на кшталт UUID, Optional та коліс дат Joda-Time.
GsonBuilder надає десятки методів для тонкого налаштування серіалізації. setPrettyPrinting додає відступи та перенесення рядків у вихідний JSON для читабельності. disableHtmlEscaping відключає екранування символів HTML у рядках. setDateFormat задає формат дат, що критично при роботі з серверами, які використовують нестандартне представлення часу. setLenient включає ослаблений режим парсингу, який ігнорує деякі помилки форматування JSON. addDeserializationExclusionStrategy дозволяє програмно виключати поля з десеріалізації на основі кастомних стратегій. Для налагодження корисний метод setPrettyPrinting у поєднанні з логуванням — він робить JSON-відповіді читабельними в логах і спрощує пошук невідповідностей.
Важлива можливість GsonBuilder — керування версійністю полів через анотації @Since та @Until. Розробник вказує версію об'єкта через setVersion, і Gson автоматично включає або виключає поля залежно від їхньої версійної анотації. Це корисно при еволюції API, коли одна й та сама модель використовується для різних версій серверного протоколу. GsonBuilder також підтримує реєстрацію TypeAdapterFactory для глобальної обробки сімейств типів та complexMapKeySerialization для коректної роботи зі складними ключами Map.
Часті запитання
Gson — це бібліотека Google для перетворення Java-об'єктів у JSON і назад. Вона широко використовується в Android-додатках для парсингу відповідей сервера, серіалізації запитів та збереження даних у локальному сховищі.
За замовчуванням Gson пропускає поля з null при серіалізації. Для включення null-значень використовуйте GsonBuilder.serializeNulls(). При десеріалізації відсутні в JSON поля залишаються null або приймають значення за замовчуванням для типу.
Moshi не використовує рефлексію для Kotlin-класів, що дає вищу продуктивність і передбачувану поведінку. Moshi також коректно обробляє null-безпеку Kotlin, тоді як Gson може десеріалізувати null у non-null поле, викликаючи виняток.
@SerializedName пов'язує JSON-ключ із полем класу, коли їхні імена не збігаються. Наприклад, для поля kotlinName та JSON-ключа "kotlin_name" анотація @SerializedName("kotlin_name") забезпечує коректне перетворення.
TypeToken — це абстрактний клас, який захоплює параметр типу через анонімний клас. Він необхідний для десеріалізації колекцій та інших параметризованих типів, оскільки через стирання типів Gson не може відновити тип елемента під час виконання.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також