# 【Kotlin】kotlinx.serialization Vs Gson

### 1. **簡介**

- **kotlinx.serialization**：介紹它是 Kotlin 官方提供的序列化庫，支持 JSON 和其他格式。
- **Gson**：介紹它是 Google 開發的 Java 序列化庫，用於將 Java 對象轉換為 JSON，反之亦然。

- **範例程式碼：**
    
    ```Java
    // kotlinx.serialization example
    @Serializable
    data class User(val name: String, val age: Int)
    
    ```
- ```Java
    // Gson example
    data class User(val name: String, val age: Int)
    
    ```
- **說明：** `kotlinx.serialization` 使用 `@Serializable` 註解來標記可序列化的類，而 Gson 則不需要特定註解（除非需要特殊處理）。

### 2. **設計理念**

- **kotlinx.serialization**：設計為 Kotlin 專用，強調與 Kotlin 語言特性的緊密集成（例如 `data classes`、`sealed classes`）。
- **Gson**：設計為通用的 Java 庫，支持多種 Java 對象類型。

- **範例程式碼：**
    
    ```Java
    // kotlinx.serialization
    val jsonStr = Json.encodeToString(User("Alice", 25))
    println(jsonStr)  // {"name":"Alice","age":25}
    
      
    // Gson
    val gson = Gson()
    val gsonStr = gson.toJson(User("Alice", 25))
    println(gsonStr)  // {"name":"Alice","age":25}
    ```
- **說明：** `kotlinx.serialization` 與 Kotlin 整合更緊密，直接使用 Kotlin 的標準庫方法，而 Gson 則是 Java 標準的物件-JSON 序列化工具。

### 3. **使用方式**

- 介紹如何在兩者中實現基本的 JSON 序列化和反序列化。
- 範例程式碼：比較使用 `@Serializable` 註解和 Gson 的 `@SerializedName` 註解。
- 依賴管理：
- ```JSON
    object Kotlin {
    	const val serializationJson 	= "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1"
    }
    
    dependencies {
    	implementation(Kotlin.serializationJson)
    }
    
    plugins {
    	kotlin("plugin.serialization") version "2.0.0"  // 添加序列化插件
    }
    ```
- ```JSON
    object Libraries {
    	const val gson 		= "com.google.code.gson:gson:2.10.1"
    }
    
    dependencies {
    	implementation(Libraries.gson)
    }
    ```
- **範例程式碼：**
    
    ```Java
    // kotlinx.serialization
    @Serializable
    data class Product(val id: Int, val name: String)
    
    val jsonString = Json.encodeToString(Product(1, "Laptop"))
    val product = Json.decodeFromString<Product>(jsonString)
    
    
    ```
- ```Java
    // Gson
    data class Product(val id: Int, val name: String)
    
    val gson = Gson()
    val jsonString = gson.toJson(Product(1, "Laptop"))
    val product = gson.fromJson(jsonString, Product::class.java)
    
    ```
- **簡短說明：** `kotlinx.serialization` 和 Gson 都可以輕鬆地進行物件與 JSON 之間的轉換，但 `kotlinx.serialization` 更加型別安全，避免了 Java 的類型擦除問題。

##### **1. 類型擦除（Type Erasure）問題**

- 當您呼叫 `toJson(obj)` 時，Gson 呼叫 `obj.getClass()` 來獲取要序列化的欄位資訊。同樣，您通常可以在 `fromJson(json, MyClass.class)` 方法中傳入 `MyClass.class` 物件。這對於非泛型類型的物件來說效果很好。然而，如果物件是泛型類型，那麼由於 Java 類型擦除，泛型類型資訊就會丟失。以下是說明這一點的範例：
- ```Java
    @Serializable
    data class People<T>(var value: T)
    @Serializable
    data class Man(val name: String)
    
       val gson = Gson()
       val people = People(Man("John"))
       gson.toJson(people) 
    
       gson.fromJson<People<Man>>(people, People::class.java) // 無法將 people.value 反序列化為 People
    ```
- 上述代碼無法將 value 解釋為 Man 類型，因為 Gson 調用 `People::class.java` 來獲取其類別資訊，但此方法返回原始類別，`People::class.java`。這意味著 Gson 無法知道這是一個 `People<Man>` 類型的物件，而不僅僅是普通的 `People`。
    
    <div><div><svg class="svg-icon" data-icon="link" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg><div> <button class="button outline icon" data-clipboard-target="#pointer-url" title="複製連結" type="button"><svg class="svg-icon" data-icon="copy" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></button></div><svg class="svg-icon" data-icon="edit" role="presentation" viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"></svg></div></div>您可以通過為您的泛型類型指定正確的參數化類型來解決這個問題。您可以使用 `TypeToken` 類別來實現這一點。
- ```Java
       val gson = Gson()
       val people = People(Man("John"))
       val peopleType = object : TypeToken<People<Man>>() {}.type
       val gsonString = gson.toJson(people, peopleType)
       println(gsonString) //{"value":{"name":"John"}}
    
       val people2 = gson.fromJson<People<Man>>(gsonString, peopleType)
       println(people2) // People(value=Man(name=John))
    ```
- ```Java
       val gson = Gson()
       val users = listOf(User("Alice",18),User("Sam",20))
       val gsonString = gson.toJson(users)
       // 序列化
       println(gsonString) // [{"name":"Alice","age":18},{"name":"Sam","age":20}]
    
       // 反序列化
       val userType = object : TypeToken<List<User>>() {}.type
    //   val users2 = gson.fromJson<List<User>>(gsonString,  List<User>::class.java)  // 無法反序列化
       val users2 = gson.fromJson<List<User>>(gsonString, userType)
       println(users2) // [User(name=Alice, age=18), User(name=Sam, age=20)]
    ```
- ```Java
    import com.google.gson.Gson
    import com.google.gson.GsonBuilder
    import com.google.gson.reflect.TypeToken
    
    val gson: Gson = GsonBuilder()
            .serializeNulls()
            .setLenient()
            .create()
    
        private val prettyGson: Gson = GsonBuilder()
            .setPrettyPrinting()
            .serializeNulls()
            .setLenient()
            .create()
    
        fun <T> fromJson(json: String, clazz: Class<T>): T {
            return gson.fromJson(json, clazz)
        }
    
        inline fun <reified T> fromJson(json: String): T {
            return gson.fromJson(json, object : TypeToken<T>() {}.type)
        }
    
        fun toJson(src: Any): String {
            return gson.toJson(src)
        }
    
        fun toPrettyJson(src: Any): String {
            return prettyGson.toJson(src)
        }
    //////////////////////////////////////////////////////////////
    
       val map = listOf(User("Alice", 25) ,User("John", 18))
       val userList = GsonUtil.fromJson<List<User>>(GsonUtil.toJson(map))
       println(userList) // [User(name=Alice, age=25), User(name=John, age=18)]
    ```

#####  

##### **2. kotlinx.serialization 的型別安全**

`kotlinx.serialization` 是 Kotlin 原生的序列化庫，它能夠利用 Kotlin 的反射和內聯函數特性在編譯時和運行時保留類型信息，避免了類型擦除問題。這意味著你可以直接在編譯期獲取類型信息，從而在運行時保留完整的類型安全性。

**範例：**

```Java
@Serializable
data class People<T>(var value: T)
@Serializable
data class Man(val name: String)
  
   val people = People(Man("John"))
   val jsonString = Json.encodeToString(people)
   println(jsonString) // {"value":{"name":"John"}}
   val people2 = Json.decodeFromString<People<Man>>(jsonString)
   println(people2) // People(value=Man(name=John))
```

在這個例子中，`kotlinx.serialization` 使用 `decodeFromString<User>(jsonString)` 方法時，直接保留了 `User` 類型的信息，而無需額外提供類型提示。這是因為 Kotlin 的 `inline` 函數和 reified 泛型可以在運行時保留類型信息。

##### **3. 優勢和好處**

- **更簡潔的代碼**：由於不需要像 Java 中那樣使用 `TypeToken`，代碼更為簡潔。
- **避免運行時錯誤**：`kotlinx.serialization` 在編譯期就可以捕獲到類型錯誤，減少了在運行時發生類型錯誤的風險。
- **原生支持 Kotlin 特性**：`kotlinx.serialization` 支持 Kotlin 的數據類（data class）、密封類（sealed class）、型別別名（type alias）等，這些在序列化時都能得到更好的支持。

### 4. **特性比較**

在 `kotlinx.serialization` 中，有多種設定可以控制 JSON 序列化和反序列化的行為，這些設定可以通過 `Json` 配置進行調整。以下是對這些設定的詳細補充說明，以及如何混合使用它們：

#### 1. **`prettyPrint`**

- **說明**：如果設置為 `true`，生成的 JSON 會以更具可讀性的格式進行縮排和換行。這對於需要易於閱讀和調試的 JSON 輸出非常有用。
- 預設值(false)
- **範例：**```Java
    val json = Json { prettyPrint = true }
    val data = json.encodeToString(User("Alice", 25))
    println(data) // 生成的 JSON 會換行和縮排
    
    /*
    {
        "name": "Alice",
        "age": 25
    }
    */
    ```
- ```Java
    val gson = GsonBuilder().setPrettyPrinting().create()
    val jsonString = gson.toJson(User("Alice", 25))
    println(jsonString)
      
    /*
    {
        "name": "Alice",
        "age": 25
    }
    */
    ```

#### 2. **`isLenient`**

- **說明**：如果設置為 `true`，反序列化時會允許 JSON 不符合嚴格的 JSON 標準。例如，允許非雙引號字符串、不轉義的控制字符等。
- **範例：**```Java
    val json = Json { isLenient = true }
    val user = json.decodeFromString<User>("""{"name":'Alice', "age":25}""")
    println(user)  // User(name=Alice, age=25)
    ```
- ```Java
       val gson = GsonBuilder()
                   .setLenient()
                   .create()
       val reader = StringReader("{'name': 'Alice', 'age': 25}")
       val user: User = gson.fromJson(reader, User::class.java)
       println(user) // User(name=Alice, age=25)
    ```
- **用途**：用於處理不符合標準的 JSON。

#### 3. **`ignoreUnknownKeys`**

- **說明**：如果設置為 `true`，反序列化時會忽略 JSON 中多餘的、不在 Kotlin 資料類中定義的鍵。
- 預設值(false)，多餘的、不在 Kotlin 資料類中定義的鍵，會拋出錯誤
- **範例：**```Java
    val json = Json { ignoreUnknownKeys = true }
    val data = json.decodeFromString<User>("""{"name":"Alice", "age":25, "gender":"female"}""")
    // User(name=Alice, age=25)
    ```
- ```Java
    // Gson 只會輸出class有的屬性，不會出現錯誤
    val gson = Gson()
       val user: User = gson.fromJson("{\"name\": \"Alice\", \"age\": 25, \"gender\": \"female\"}", User::class.java)
       println(user) // User(name=Alice, age=25)
    ```
- **用途**：用於處理結構可能有變化或不完整的 JSON 資料。

#### 4. **`@JsonNames`**

- **說明**：用於指定多個 JSON 欄位名可以對應於 Kotlin 類中的同一屬性。這對於處理不同命名風格或版本兼容性非常有用。
- **範例：**```Java
    @Serializable
    data class User(
        @JsonNames("username", "user_name","uname")
        val name: String,
        val age: Int
    )
    
    val json = Json{}
      
    val User = Json.encodeToString(User("mary", 20))
    println(User) // {"name":"mary","age":20}
      
    val jsonNamesData = json.decodeFromString<User>("""{"uname":"Alice", "age":25, "gender":"female"}""")
    println(jsonNamesData) // User(name=Alice, age=25)
    
    ```
- ```Java
    import com.google.gson.annotations.SerializedName
    
    data class User(
        @SerializedName(value = "user_name", alternate = ["username", "userName"])
        val name: String,
        val age: Int
    )
    
    // 序列化
    val jsonString = """{"user_name": "Alice", "age": 25}"""
    val gson = Gson()
    val user: User = gson.fromJson(jsonString, User::class.java)
    println(user.name)  // Output: Alice
    
    // 反序列化
    val user = User(name = "Alice", age = 25)
    val gson = Gson()
    val jsonString = gson.toJson(user)
    println(jsonString)  // Output: {"user_name":"Alice","age":25}
    
    ```
- **用途**：用於不同 JSON 格式之間的兼容性。

#### 5. **`encodeDefaults`**

- **說明**：如果設置為 `true`，則在序列化時會包含所有屬性，即使它們具有預設值；如果為 `false`，則省略具有預設值的屬性。  
    預設輸出預設值(false)
- **範例：**```Java
    data class User(
       @JsonNames("username", "user_name", "uname")
       val name: String,
       val age: Int = 30
    )
    
    val json = Json { encodeDefaults = true }
    val data = json.encodeToString(User("Alice"))
    
    //    encodeDefaults = true
    //   {
    //      "name": "Alice",
    //      "age": 30
    //   }
      
    //    encodeDefaults = false (default)
    //   {
    //      "name": "Alice"
    //   }
    ```
- ```Java
    // 說明：Gson 不會使用 Kotlin 的預設參數值,
    // 想要預設值需要自定義序列化器
        val userSerializer = JsonSerializer<User> { src, _, _ ->
          val DEFAULT_AGE = 30
          val jsonObject = JsonObject()
          jsonObject.addProperty("name", src.name)
          if (src.age != DEFAULT_AGE) { // 檢查 age 是否為預設值
             jsonObject.addProperty("age", src.age)
          }
          jsonObject
        }
    
        // 創建 Gson 並註冊自定義序列化器
        val gson = GsonBuilder()
            .registerTypeAdapter(User::class.java, userSerializer)
            .create()
    
        val alice = User("Alice")
        val jsonString = gson.toJson(alice)
        println(jsonString) // Output: {"name":"Alice"}
          
        val tom = User("Tom",18)
        val jsonString2 = gson.toJson(tom)
        println(jsonString2) // Output: {"name":"Tom","age":18}
    ```
- ##### 直接隱藏屬性
- ```Java
    import com.google.gson.Gson
    import com.google.gson.GsonBuilder
    import java.lang.reflect.Modifier
    import kotlinx.serialization.Transient
    
    // Ｇson 或是使用 @Transient 註解 + excludeFieldsWithModifiers 排除屬性
    // kotlinx.serialization 也可以用此註解，效果一樣
    data class User(
        val name: String,
        @Transient val age: Int = 30 // 被 transient 修飾符修飾
    ) {
        companion object {
            const val COMPANY = "ExampleCompany"  // 靜態屬性，將被排除
        }
    }
    
    fun main() {
        val gson: Gson = GsonBuilder()
            .excludeFieldsWithModifiers(Modifier.TRANSIENT, Modifier.STATIC) // 排除 transient 和 static 修飾符的屬性
            .create()
    
        val user = User(name = "Alice")
        val jsonString = gson.toJson(user)
    
        println(jsonString) // {"name":"Alice"}
          
        // kotlinx.serialization 也可以用此註解，效果一樣
        println(Json.encodeToString(user)) // Output: {"name":"Alice"}
    }
    
    ```
- **用途**：控制 JSON 中輸出的詳細程度。

#### 6. **`explicitNulls`**

- **說明**：如果設置為 `false`，序列化時將省略值為 `null` 的屬性；如果設置為 `true`，則會顯示 `null` 值。  
    預設(false)不輸出null
- **範例：**```Java
    val json = Json { explicitNulls = true }
    val data = json.encodeToString(User("Alice", null))
      
    //   {
    //      "name": "Alice",
    //      "age": 25,
    //      "nickName": null
    //   }
    
    ```
- ```Java
    data class User2(
    //   @JsonNames("username", "user_name", "uname")
       val name: String,
       val age: Int? = null,
       val nickName: String? = null
    )
    
    val gsonIncludeNulls = GsonBuilder().serializeNulls().create() // 包含 null
    val gsonExcludeNulls = GsonBuilder().create() // 排除 null
    
    println(gsonIncludeNulls.toJson(User("Alice", 12, null))) 
      // {"name":"Alice","age":12,"nickName":null}
      
    println(gsonExcludeNulls.toJson(User("Alice", 13, null))) 
      // {"name":"Alice","age":13}
    
    ```
- **用途**：控制如何處理 `null` 值，特別是在需要減少 JSON 大小時。

#### 7. **`allowStructuredMapKeys`**

- **說明**：如果設置為 `true`，允許使用複雜類型（例如，資料類）作為 Map 的鍵；否則僅允許基本類型作為鍵。
- **範例：**```Java
    val json = Json { allowStructuredMapKeys = true }
    val data = json.encodeToString(mapOf(User("Alice", 25) to "Developer"))
    
    /*
    [
        {
            "name": "Alice",
            "age": 25
        },
        "Developer"
    ]
    */
    ```
- ```Java
    // Gson 不直接支持複雜類型作為 Map 的鍵。通常需要將 Map 鍵轉換為字串形式：
    data class User(val name: String, val age: Int)
    val gson = GsonBuilder().create()
    val map = mutableMapOf(gson.toJson(User("Alice", 25)) to "Developer")
    val jsonString = gson.toJson(map) 
      // {"{\"name\":\"Alice\",\"age\":25}":"Developer"}
    
    ```
- ```Java
    // 使用 enableComplexMapKeySerialization 會有以意料之外結果
       val gson = GsonBuilder()
          .enableComplexMapKeySerialization()
          .create()
    
       val map = mutableMapOf(User("Alice", 25) to "Developer")
       println(map) // {User(name=Alice, age=25)=Developer}
       println(gson.toJson(map)) // [[{"name":"Alice","age":25},"Developer"]]
    /*    
    
    當你使用 enableComplexMapKeySerialization() 時，
    Gson 允許序列化包含複雜對象（例如，自定義的 User 類型）作為鍵的 Map。默認情況下，Gson 只能處理字符串等基本類型作為鍵。
    Gson 序列化 Map 時，會將鍵和值分別序列化。當使用複雜對象作為鍵時，Gson 會將這些鍵作為 JSON 的單獨條目來處理。
    
    由於 User("Alice", 25) 是一個非基本類型對象，Gson 將其序列化為 {"name":"Alice","age":25}，
    而 Map 的結果被序列化為包含鍵值對的數組。
    
    當你打印 gson.toJson(map) 時，結果是 [[{"name":"Alice","age":25},"Developer"]]，
    這意味著 JSON 的輸出是一個數組，數組中包含了鍵和值的另一個數組。
    這是因為 Gson 使用 List（一種數組結構）來表示 Map 的鍵值對，特別是在鍵是非基本類型的情況下。
    
    */
         
       val map = mutableMapOf(User("Alice", 25) to "Developer",User("John", 18) to "Student")
       println(map)
         // {User(name=Alice, age=25)=Developer, User(name=John, age=18)=Student}
       println(gson.toJson(map))
         // [[{"name":"Alice","age":25},"Developer"],[{"name":"John","age":18},"Student"]]
    ```
- **用途**：用於需要使用複雜鍵的 JSON 結構。

#### 8. **`allowSpecialFloatingPointValues`**

- **說明**：如果設置為 `true`，允許特殊的浮點數值（例如，NaN、Infinity）在 JSON 中表示；如果為 `false`，則會拋出錯誤。
- **範例：**```Java
    val json = Json { allowSpecialFloatingPointValues = true }
    val data = json.encodeToString(Double.POSITIVE_INFINITY)
    
    // Infinity
    ```
- ```Java
    val gson = GsonBuilder()
        .registerTypeAdapter(Double::class.java, JsonSerializer<Double> { src, _, _ ->
            when {
                src.isNaN() || src.isInfinite() -> JsonPrimitive(src.toString())
                else -> JsonPrimitive(src)
            }
        })
        .registerTypeAdapter(Double::class.java, JsonDeserializer { json, _, _ ->
            when (val value = json.asString) {
                "NaN" -> Double.NaN
                "Infinity" -> Double.POSITIVE_INFINITY
                "-Infinity" -> Double.NEGATIVE_INFINITY
                else -> value.toDouble()
            }
        })
        .create()
    
    ```
- **用途**：用於需要表示特殊浮點值的 JSON 序列化和反序列化。

#### **如何混合使用這些配置**

你可以將這些配置項混合使用來滿足特定的序列化和反序列化需求。

例如，假設你有一個情況需要反序列化<span style="background-color: #fbeeb8;">非標準的 JSON</span> 資料，並且需要<span style="background-color: #fbeeb8;">忽略未知的鍵</span>且<span style="background-color: #fbeeb8;">保留結構化的 Map 鍵：</span>

```Java
val json = Json {
    prettyPrint = true
    isLenient = true
    ignoreUnknownKeys = true
    encodeDefaults = false
    explicitNulls = false
    coerceInputValues = true
    allowStructuredMapKeys = true
    allowSpecialFloatingPointValues = true
}

val data = json.decodeFromString<User>("""{"name":"Alice", "unknownField":"value"}""")
println(data)
// User(name=Alice, age=30)

```

```Java
val gson = GsonBuilder()
    .setPrettyPrinting()
    .setLenient()
    .serializeNulls()  // Include nulls
    .registerTypeAdapter(User::class.java, JsonDeserializer { json, _, _ ->
        val jsonObject = json.asJsonObject
        val name = if (jsonObject.has("name")) jsonObject["name"].asString else "DefaultName"
        val age = if (jsonObject.has("age")) jsonObject["age"].asInt else 30 // Default value
        User(name, age)
    })
    .create()

val jsonString = """{"name":"Alice","unknownField":"value"}"""
val user: User = gson.fromJson(jsonString, User::class.java)
println(user) //User(name=Alice, age=30)
println(gson.toJson(User("Alice")))
  /*
  {
    "name": "Alice",
    "age": 30
  }
  */
```

在這個例子中，我們結合了多種配置來實現靈活且容錯的 JSON 解析和輸出，確保代碼能夠應對多種 JSON 格式和數據問題。這樣的設置可以讓你的應用更加健壯和靈活。

json default value:

```Java
/**
 * Configuration of the current [Json] instance available through [Json.configuration]
 * and configured with [JsonBuilder] constructor.
 *
 * Can be used for debug purposes and for custom Json-specific serializers
 * via [JsonEncoder] and [JsonDecoder].
 *
 * Standalone configuration object is meaningless and can nor be used outside the
 * [Json], neither new [Json] instance can be created from it.
 *
 * Detailed description of each property is available in [JsonBuilder] class.
 */
public class JsonConfiguration @OptIn(ExperimentalSerializationApi::class) internal constructor(
    public val encodeDefaults: Boolean = false,
    public val ignoreUnknownKeys: Boolean = false,
    public val isLenient: Boolean = false,
    public val allowStructuredMapKeys: Boolean = false,
    public val prettyPrint: Boolean = false,
    public val explicitNulls: Boolean = true,
    @ExperimentalSerializationApi
    public val prettyPrintIndent: String = "    ",
    public val coerceInputValues: Boolean = false,
    public val useArrayPolymorphism: Boolean = false,
    public val classDiscriminator: String = "type",
    public val allowSpecialFloatingPointValues: Boolean = false,
    public val useAlternativeNames: Boolean = true,
    @ExperimentalSerializationApi
    public val namingStrategy: JsonNamingStrategy? = null,
    @ExperimentalSerializationApi
    public val decodeEnumsCaseInsensitive: Boolean = false,
    @ExperimentalSerializationApi
    public val allowTrailingComma: Boolean = false,
    @ExperimentalSerializationApi
    public val allowComments: Boolean = false,
    @ExperimentalSerializationApi
    @set:Deprecated(
        "JsonConfiguration is not meant to be mutable, and will be made read-only in a future release. " +
            "The `Json(from = ...) {}` copy builder should be used instead.",
        level = DeprecationLevel.ERROR
    )
    public var classDiscriminatorMode: ClassDiscriminatorMode = ClassDiscriminatorMode.POLYMORPHIC,
) {

    /** @suppress Dokka **/
    @OptIn(ExperimentalSerializationApi::class)
    override fun toString(): String {
        return "JsonConfiguration(encodeDefaults=$encodeDefaults, ignoreUnknownKeys=$ignoreUnknownKeys, isLenient=$isLenient, " +
                "allowStructuredMapKeys=$allowStructuredMapKeys, prettyPrint=$prettyPrint, explicitNulls=$explicitNulls, " +
                "prettyPrintIndent='$prettyPrintIndent', coerceInputValues=$coerceInputValues, useArrayPolymorphism=$useArrayPolymorphism, " +
                "classDiscriminator='$classDiscriminator', allowSpecialFloatingPointValues=$allowSpecialFloatingPointValues, " +
                "useAlternativeNames=$useAlternativeNames, namingStrategy=$namingStrategy, decodeEnumsCaseInsensitive=$decodeEnumsCaseInsensitive, " +
                "allowTrailingComma=$allowTrailingComma, allowComments=$allowComments, classDiscriminatorMode=$classDiscriminatorMode)"
    }
}
```

---

### 5. **擴展性和客製化**

在 JSON 序列化和反序列化過程中，`kotlinx.serialization` 和 Gson 都提供了強大的擴展性和客製化能力。這些能力允許開發者根據需要定義自定義的序列化和反序列化邏輯，以處理特殊格式的數據或滿足特定需求。

#### **kotlinx.serialization 的擴展性和客製化**

`kotlinx.serialization` 提供了一個簡潔的方式來自定義序列化和反序列化邏輯，通過實作 `KSerializer` 介面，你可以完全控制對象的序列化和反序列化過程。

##### **如何實作自定義序列化器**

1. **定義資料類**：
    
    ```Java
    @Serializable
    data class Event(val name: String,
                     @Serializable(with = DateSerializer::class) val date: Date)
    
    
    ```
    
    在這個例子中，`Event` 類的 `date` 屬性使用了自定義序列化器 `DateSerializer` 來處理 `Date` 類型。
2. **實作 `KSerializer` 介面**：
    
    ```Java
    object DateSerializer : KSerializer<Date> {
        override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Date", PrimitiveKind.STRING)
    
        override fun serialize(encoder: Encoder, value: Date) {
            // 自定義的序列化邏輯，將 Date 轉換為 String
            val dateFormat = SimpleDateFormat("yyyy-MM-dd")
            val dateString = dateFormat.format(value)
            encoder.encodeString(dateString)
        }
    
        override fun deserialize(decoder: Decoder): Date {
            // 自定義的反序列化邏輯，將 String 轉換為 Date
            val dateFormat = SimpleDateFormat("yyyy-MM-dd")
            val dateString = decoder.decodeString()
            return dateFormat.parse(dateString)
        }
    }
    
    ```
    
    在這個例子中：
    
    
    - `serialize` 方法將 `Date` 對象序列化為 `String` 格式。
    - `deserialize` 方法將 `String` 反序列化為 `Date` 對象。
3. **使用自定義序列化器**：
    
    ```Java
    val json = Json { }
    val event = Event("Conference", Date())
    val jsonString = json.encodeToString(event)
    println(jsonString) // {"name":"Conference","date":"2024-08-29"}
    
    val deserializedEvent = json.decodeFromString<Event>(jsonString)
    println(deserializedEvent)
    // Event(name=Conference, date=Thu Aug 29 00:00:00 CST 2024)
    ```
    
    自定義序列化器 `DateSerializer` 會自動在 `encodeToString` 和 `decodeFromString` 操作中被使用，處理 `Event` 類中的 `date` 屬性。

#### **Gson 的擴展性和客製化**

在 Gson 中，客製化序列化和反序列化是通過實作 `JsonSerializer` 和 `JsonDeserializer` 介面來實現的。這提供了類似的靈活性，可以完全控制對象的序列化和反序列化過程。

##### **如何實作自定義序列化器和反序列化器**

1. **定義資料類**：
    
    ```
    data class Event(val name: String, val date: Date)
    
    ```
    
    與 `kotlinx.serialization` 不同，Gson 並不需要在資料類上添加任何特別的註解。
2. **實作 `JsonSerializer` 和 `JsonDeserializer` 介面**：
    
    ```Java
    val dateSerializer = JsonSerializer<Date> { src, _, _ ->
        // 自定義的序列化邏輯，將 Date 轉換為 String
        val dateFormat = SimpleDateFormat("yyyy-MM-dd")
        JsonPrimitive(dateFormat.format(src))
    }
    
    val dateDeserializer = JsonDeserializer<Date> { json, _, _ ->
        // 自定義的反序列化邏輯，將 String 轉換為 Date
        val dateFormat = SimpleDateFormat("yyyy-MM-dd")
        dateFormat.parse(json.asString)
    }
    
    ```
    
    在這個例子中：
    
    
    - `dateSerializer` 是一個 `JsonSerializer<Date>`，負責將 `Date` 序列化為 JSON 字符串。
    - `dateDeserializer` 是一個 `JsonDeserializer<Date>`，負責將 JSON 字符串反序列化為 `Date` 對象。
3. **使用自定義序列化器和反序列化器**：
    
    ```Java
    val gson = GsonBuilder()
        .registerTypeAdapter(Date::class.java, dateSerializer)
        .registerTypeAdapter(Date::class.java, dateDeserializer)
        .create()
    
    val event = Event("Conference", Date())
    val jsonString = gson.toJson(event)
    println(jsonString)
      // {"name":"Conference","date":"2024-08-29"}
    
    val deserializedEvent = gson.fromJson(jsonString, Event::class.java)
    println(deserializedEvent)
     // Event(name=Conference, date=Thu Aug 29 00:00:00 CST 2024)
    ```
    
    在這個例子中，`registerTypeAdapter` 方法用來註冊自定義的序列化器和反序列化器。Gson 會在序列化和反序列化 `Date` 類型時使用這些自定義的邏輯。

#### **總結**

- **`kotlinx.serialization` 的擴展性和客製化**：使用 `KSerializer` 介面來定義自定義的序列化和反序列化邏輯。這種方法能夠充分利用 Kotlin 的語言特性，如型別安全和編譯期檢查，確保序列化和反序列化過程中不會發生類型錯誤。
- **Gson 的擴展性和客製化**：使用 `JsonSerializer` 和 `JsonDeserializer` 介面來實現自定義的序列化和反序列化邏輯。Gson 的這種設計讓開發者可以非常靈活地處理各種數據格式和需求，特別是在 Java 環境中使用時。

這兩者都提供了足夠的靈活性來滿足大多數序列化和反序列化需求，不過 `kotlinx.serialization` 更加貼合 Kotlin 語言的特性和風格，而 Gson 則更加通用且適用於 Java 開發環境。

### 6. **依賴管理與體積**

- **範例程式碼：**
    
    ```Java
    // kotlinx.serialization
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0"
    
    // Gson
    implementation 'com.google.code.gson:gson:2.9.0'
    
    ```
- #### **kotlinx.serialization**
    
    
    - **依賴體積**：`kotlinx.serialization` 是 Kotlin 官方提供的庫，專為 Kotlin 設計。這意味著它在體積上相對輕量，因為它不需要額外的依賴來運行 Kotlin 特性。它也不需要引入 Java 標準庫以外的額外依賴。
    - **依賴管理**：`kotlinx.serialization` 的版本更新和依賴管理與 Kotlin 生態系統的版本緊密相關。它由 JetBrains 官方維護，更新相對頻繁，且通常會與 Kotlin 編譯器的更新一起釋出，這意味著使用者需要隨時注意 Kotlin 版本的變化。
    - **優勢**：
        
        
        - **與 Kotlin 無縫集成**：`kotlinx.serialization` 是一個 Kotlin 原生庫，它與 Kotlin 語言特性（如 data class、sealed class）無縫集成。
        - **輕量且效能優化**：由於其緊密結合的 Kotlin 庫體積較小，並且效能優化專門針對 Kotlin 特性，這使得它在 Kotlin 開發中非常高效。
        - **易於在多平台項目中使用**：`kotlinx.serialization` 支持 Kotlin Multiplatform，因此它可以在同一套代碼中使用於 Android、iOS 和其他平台。
    - **劣勢**：
        
        
        - **僅適用於 Kotlin 項目**：由於其與 Kotlin 的深度集成，如果你的項目是基於 Java 的，將不適合使用 `kotlinx.serialization`。
    
    #### **Gson**
    
    
    - **依賴體積**：Gson 是一個通用的 Java 庫，設計用來支持各種 Java 對象的序列化和反序列化。由於它的廣泛兼容性和全面功能，Gson 的依賴體積相對較大，包含許多標準庫來處理各種情境。
    - **依賴管理**：Gson 是由 Google 開發和維護的開源項目，但它的更新頻率比 `kotlinx.serialization` 要低。Gson 的版本變更通常是為了修復錯誤或增強功能，而不是頻繁的版本更新。
    - **優勢**：
        
        
        - **廣泛的兼容性**：作為一個 Java 庫，Gson 可以在任何 Java 環境中使用，包括 Kotlin 開發中。它可以處理 Java 的各種類型和情況，如泛型、嵌套類型等。
        - **功能全面且穩定**：Gson 在處理複雜 JSON 結構時非常靈活，並且提供了豐富的自定義擴展選項（如自定義序列化和反序列化）。
        - **廣泛的社群支持**：由於它的廣泛使用和成熟度，Gson 擁有大量的使用者和豐富的社群資源，許多常見問題和挑戰都有現成的解決方案。
    - **劣勢**：
        
        
        - **較大的依賴體積**：相比 `kotlinx.serialization`，Gson 的依賴更大，這可能會對應用的 APK 體積有影響，特別是在 Android 開發中。
        - **較少的 Kotlin 特性支持**：雖然 Gson 可以用於 Kotlin 項目，但它並沒有 `kotlinx.serialization` 對 Kotlin 特性的原生支持，如 `sealed class` 和 `data class`。

### 7. **社群與支援**

- **簡短說明：** `kotlinx.serialization` 有官方支持且定期更新，更適合與 Kotlin 生態系統一起使用；Gson 有更長的歷史和廣泛的使用者社群，但更新頻率較低。

### 8. **總結與建議**

- **簡短說明：** 根據項目的需要選擇適合的工具。對於需要與 Kotlin 深度集成的應用，建議使用 `kotlinx.serialization`；如果需要支持更廣泛的 Java 類型或已有 Gson 的基礎設施，可以選擇 Gson。