1. Gson-a giriş
Artıq Jackson ilə tanış olmuşuq və niyə Java-da JSON ilə işləmək üçün de-fakto standart sayıldığını görmüşük. Amma başqa bir kitabxana da var ki, xüsusilə Android dünyasında böyük populyarlıq qazanıb — bu da Gson-dur. Gson Google-da Java obyektlərini JSON-a seriyalaşdırmaq və deserializasiya etmək üçün yüngül və sadə həll kimi yaradılıb. Onu aşağı giriş həddi üçün qiymətləndirirlər: başlamaq üçün demək olar ki, heç nəyi qurmağa ehtiyac yoxdur — tapşırıqların əksəriyyəti sözün əsl mənasında “qutudan çıxan kimi” həll olunur.
Gson-un başqa bir üstünlüyü onun yüngüllüyüdür. Kitabxana az yer tutur və çoxlu asılılıqları özü ilə gətirmir, buna görə də tətbiqin ölçüsünün kritik olduğu yerlərdə, məsələn, mobil cihazlarda tez-tez istifadə olunur. Gson Android layihələri üçün faktiki standart olub — kompaktlıq və sadəlik orada həlledici rol oynayır.
Yeri gəlmişkən, Gson adı Google JSON kimi açılır. Bəzən icmada zarafatcıl izahata da rast gəlinir — Genius’ Son (“dahinin oğlu”), amma bu, əlbəttə ki, rəsmi deyil. Sadəcə söz oyunudur.
Gson-u layihəyə qoşmaq
Əgər Maven və ya Gradle istifadə edirsinizsə, sadəcə asılılığı əlavə edin (versiya fərqli ola bilər):
Maven:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
Gradle:
implementation 'com.google.code.gson:gson:2.10.1'
Biz hələ layihələrin yığılmasını öyrənməmişik, ona görə başlanğıc üçün jar faylını sadəcə Gson-un rəsmi səhifəsindən endirib layihəyə əlavə edə bilərsiniz.
2. Baza əməliyyatlar: seriyalaşdırma və deserializasiya
Gəlin Gson ilə obyektləri necə seriyalaşdırmaq və deserializasiya etmək olar, sadə bir sinif nümunəsində baxaq.
Nümunə: User sinfi
// Nümunələr üçün sinif
public class User {
private String name;
private int age;
private boolean active;
// Konstruktor
public User(String name, int age, boolean active) {
this.name = name;
this.age = age;
this.active = active;
}
// Getter və setterlər (Gson ehtiyac olduqda onlardan istifadə edir)
public String getName() { return name; }
public int getAge() { return age; }
public boolean isActive() { return active; }
}
Seriyalaşdırma: obyekt → JSON
import com.google.gson.Gson;
public class GsonExample {
public static void main(String[] args) {
User user = new User("Alice", 25, true);
Gson gson = new Gson();
String json = gson.toJson(user);
System.out.println(json);
// {"name":"Alice","age":25,"active":true}
}
}
Diqqət yetirin: sahələr sinifdəki adları ilə seriyalaşdırılır!
Deserializasiya: JSON → obyekt
public class GsonExample {
public static void main(String[] args) {
String json = "{\"name\":\"Bob\",\"age\":30,\"active\":false}";
Gson gson = new Gson();
User user = gson.fromJson(json, User.class);
System.out.println(user.getName()); // Bob
System.out.println(user.getAge()); // 30
System.out.println(user.isActive());// false
}
}
Obyekt siyahıları ilə iş
Gson kolleksiyalarla Jackson-a nisbətən bir az daha mürəkkəb işləyir, amma hər şey həll olunur.
import java.util.List;
import java.util.Arrays;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
public class GsonListExample {
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("Alice", 25, true),
new User("Bob", 30, false)
);
Gson gson = new Gson();
String json = gson.toJson(users);
System.out.println(json);
// [{"name":"Alice","age":25,"active":true},{"name":"Bob","age":30,"active":false}]
// Siyahının deserializasiyası
Type userListType = new TypeToken<List<User>>(){}.getType();
List<User> users2 = gson.fromJson(json, userListType);
System.out.println(users2.get(0).getName()); // Alice
}
}
Vacib məqam: kolleksiyaları deserializasiya etmək üçün TypeToken<> istifadə edin!
3. Gson-un konfiqurasiyası: GsonBuilder
Gson çevik tənzimləməni GsonBuilder sinfi vasitəsilə təqdim edir. Onunla pretty printing-i aktivləşdirə, null seriyalaşdırılmasını, tarixlərin formatlanmasını və daha çoxunu qura bilərsiniz.
Nümunə: pretty printing və null-un seriyalaşdırılması
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class GsonBuilderExample {
public static void main(String[] args) {
User user = new User("Charlie", 0, false);
Gson gson = new GsonBuilder()
.setPrettyPrinting() // Səliqəli çıxış (girintilər)
.serializeNulls() // null sahələri seriyalaşdırmaq
.create();
String json = gson.toJson(user);
System.out.println(json);
/*
{
"name": "Charlie",
"age": 0,
"active": false
}
*/
}
}
Tarixlərin formatlanması
Əgər sizdə Date tipli sahələr varsa, standartda Gson onları spesifik formatda seriyalaşdırır. Öz formatınızı təyin edə bilərsiniz:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.Date;
public class DateExample {
private String event;
private Date date;
public DateExample(String event, Date date) {
this.event = event;
this.date = date;
}
}
public class Main {
public static void main(String[] args) {
DateExample meeting = new DateExample("Team Meeting", new Date());
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd HH:mm:ss")
.create();
String json = gson.toJson(meeting);
System.out.println(json);
// {"event":"Team Meeting","date":"2024-06-10 13:45:23"}
}
}
4. Gson annotasiyaları: seriyalaşdırmaya nəzarət
Gson seriyalaşdırma və deserializasiyaya daha dəqiq nəzarət üçün annotasiyaları dəstəkləyir.
@SerializedName — sahənin adını dəyişmək
Əgər JSON-da sahənin başqa adla adlandırılmasını istəyirsinizsə, @SerializedName istifadə edin:
import com.google.gson.annotations.SerializedName;
public class User {
@SerializedName("full_name")
private String name;
private int age;
private boolean active;
public User(String name, int age, boolean active) {
this.name = name;
this.age = age;
this.active = active;
}
}
İndi seriyalaşdırma zamanı sahənin adı full_name olacaq:
User user = new User("Diana", 28, true);
String json = new Gson().toJson(user);
// {"full_name":"Diana","age":28,"active":true}
@Expose — yalnız işarələnmiş sahələrin seriyalaşdırılması
Yalnız müəyyən sahələri seriyalaşdırmaq istəyirsinizsə, @Expose istifadə edin və Gson-u uyğun qurun:
import com.google.gson.annotations.Expose;
public class User {
@Expose
private String name;
@Expose
private int age;
private boolean active; // seriyalaşdırılmır
public User(String name, int age, boolean active) {
this.name = name;
this.age = age;
this.active = active;
}
}
@Expose dəstəyi ilə Gson yaradırıq:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
User user = new User("Eve", 21, false);
String json = gson.toJson(user);
// {"name":"Eve","age":21}
@Since/@Until — versiyaya görə şərti seriyalaşdırma
@Since və @Until-dən yalnız müəyyən versiyalar üçün sahələrin seriyalaşdırılması məqsədilə istifadə etmək olar (praktikada nadir hallarda tətbiq olunur, amma bilmək faydalıdır).
5. Gson-un xüsusiyyətləri və məhdudiyyətləri
Daxili obyektlərlə iş
Gson daxili obyektlərlə əla işləyir:
public class Profile {
private User user;
private String bio;
public Profile(User user, String bio) {
this.user = user;
this.bio = bio;
}
}
Profile profile = new Profile(new User("Frank", 27, true), "Java developer");
String json = new Gson().toJson(profile);
// {"user":{"name":"Frank","age":27,"active":true},"bio":"Java developer"}
Kolleksiyalarla iş
Kolleksiyaların (List, Map) seriyalaşdırılmasında problem yoxdur, amma deserializasiya üçün TypeToken istifadə edin (yuxarıya baxın).
Gson-un Jackson-la müqayisədə məhdudiyyətləri
- Java record sinifləri üçün dəstək yoxdur (son versiyalara qədər)
- Yeni tarix/zaman API-larına məhdud dəstək (məsələn, LocalDate, LocalDateTime — xüsusi adapterlər lazımdır)
- Jackson annotasiyaları ilə işləyə bilmir
- Mürəkkəb polimorf strukturlar üçün “qutudan çıxan kimi” dəstək yoxdur
- İkitərəfli istinadlar (döngüsellik) üçün avtomatik dəstək yoxdur
Fərdi (custom) adapterlər (TypeAdapter)
Standart imkanlar kifayət etmirsə, mürəkkəb tiplərin seriyalaşdırılması/deserializasiyası üçün öz adapterinizi yaza bilərsiniz.
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
public class BooleanAsIntAdapter extends TypeAdapter<Boolean> {
@Override
public void write(JsonWriter out, Boolean value) throws IOException {
out.value(value ? 1 : 0);
}
@Override
public Boolean read(JsonReader in) throws IOException {
return in.nextInt() == 1;
}
}
// İstifadə:
Gson gson = new GsonBuilder()
.registerTypeAdapter(Boolean.class, new BooleanAsIntAdapter())
.create();
6. Təcrübə: parametrlərlə seriyalaşdırma və deserializasiya
Gəlin tədris tətbiqinizi inkişaf etdirək və istifadəçilər siyahısının JSON formatında saxlanmasını və yüklənməsini əlavə edək.
Annotasiyalı User sinfi
import com.google.gson.annotations.SerializedName;
import com.google.gson.annotations.Expose;
public class User {
@Expose
@SerializedName("full_name")
private String name;
@Expose
private int age;
private boolean active; // seriyalaşdırılmır
public User(String name, int age, boolean active) {
this.name = name;
this.age = age;
this.active = active;
}
// getterlər, setterlər...
}
İstifadəçilər siyahısını JSON-a saxlayırıq
import java.util.List;
import java.util.Arrays;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class SaveUsers {
public static void main(String[] args) {
List<User> users = Arrays.asList(
new User("Ivan", 23, true),
new User("Olga", 19, false)
);
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.setPrettyPrinting()
.create();
String json = gson.toJson(users);
System.out.println(json);
/*
[
{
"full_name": "Ivan",
"age": 23
},
{
"full_name": "Olga",
"age": 19
}
]
*/
}
}
İstifadəçilər siyahısını JSON-dan yükləyirik
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
public class LoadUsers {
public static void main(String[] args) {
String json = "[{\"full_name\":\"Ivan\",\"age\":23},{\"full_name\":\"Olga\",\"age\":19}]";
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
Type userListType = new TypeToken<List<User>>(){}.getType();
List<User> users = gson.fromJson(json, userListType);
for (User user : users) {
System.out.println(user.getName() + " (" + user.getAge() + ")");
}
// Ivan (23)
// Olga (19)
}
}
7. Gson və Jackson-un müqayisəsi
| Xüsusiyyət | Gson | Jackson |
|---|---|---|
| İstifadə rahatlığı | +++++ (çox sadə) | +++ (bir az daha çətindir) |
| Kitabxananın ölçüsü | Kiçik | Daha böyük |
| Sürət | Sürətli, amma bir az yavaşdır | Çox sürətli |
| Çeviklik | Orta | Yüksək (daha çox tənzimləmə) |
| Annotasiyalara dəstək | Öz annotasiyaları (@SerializedName) | Öz annotasiyaları (@JsonProperty və s.) |
| Yeni tiplərə dəstək | Məhduddur | Möhtəşəm (Java 8+, record) |
| Android dəstəyi | Möhtəşəm | Yaxşı, amma daha ağırdır |
| Tarixlərlə iş | Yalnız adapterlərlə | Qutudan çıxan kimi |
| Polimorfizm | Məhduddur | Çevik şəkildə tənzimlənir |
8. Gson ilə işləyərkən tipik səhvlər
Səhv №1: Kolleksiyalar üçün TypeToken istifadə etmirsiniz.
Əgər siyahı və ya xəritəni deserializasiya edirsinizsə, mütləq TypeToken<> istifadə edin, əks halda qəribə xətalar və ya boş kolleksiyalar əldə edəcəksiniz.
Səhv №2: Parametrsiz konstruktor yoxdur.
Gson susmaya görə konstruktor olmadan da işləyə bilər, amma bəzən mürəkkəb obyektlərin deserializasiyasında belə konstruktor olmadıqda xətalar yarana bilər. Deserializasiya planlayırsınızsa, həmişə parametrsiz konstruktor əlavə etmək daha yaxşıdır.
Səhv №3: Sahə adlarının uyğun gəlməməsi.
Əgər JSON-da sahənin adı "full_name", sinifdə isə — "name"dirsə, @SerializedName("full_name") annotasiyası olmadan sahə bağlanmayacaq və dəyər null olacaq.
Səhv №4: Private sahələrlə problemlər.
Gson private sahələri seriyalaşdıra bilir, amma yalnız private sahələr və heç bir getter/setter yoxdursa, bəzən deserializasiya zamanı problemlər yaranır. Getter və setterlərdən istifadə etmək daha yaxşıdır.
Səhv №5: Tarixlərlə iş.
Susmaya görə Gson Date-i əlverişsiz formatda seriyalaşdırır. LocalDate, LocalDateTime və digər yeni tiplər üçün xüsusi adapterlər olmadan seriyalaşdırma xətaları olacaq.
Səhv №6: @Expose istifadə etmirsiniz, amma excludeFieldsWithoutExposeAnnotation() aktivdir.
Əgər siz excludeFieldsWithoutExposeAnnotation()-u aktiv etmisinizsə, amma sahələri @Expose annotasiyası ilə işarələməmisinizsə, onlar nə seriyalaşdırılacaq, nə də deserializasiya olunacaq — nəticə boş JSON və ya sahələri null olan obyektlər olacaq.
GO TO FULL VERSION