序列化 数据库 持久化
本文的重点 (Takeaway From the Article)
By the end of this article, you’ll learn why Kotlin's team created a new serialization library despite having many advanced libraries like Moshi and Gson. Along with that, you’ll also learn how to use a native serialization library, and if you’re patient enough to read to the end, you might also know the hidden features of native serialization. Read on to learn about them.
在本文结尾,您将了解为何Kotlin的团队创建了一个新的序列化库,尽管拥有许多高级库,例如Moshi和Gson 。 除此之外,您还将学习如何使用本机序列化库,如果您足够耐心地阅读到最后,您可能还知道本机序列化的隐藏功能。 继续阅读以了解它们。
为什么Kotlin团队创建新的序列化库 (Why the Kotlin Team Created a New Serialization Library)
We have many famous and effective serialization libraries out there, like Moshi from Square and Gson from Google. But the Kotlin team decided to create a brand new native serialization library for Kotlin. The question is, why?
我们有许多著名且有效的序列化库,例如Square的Moshi和Google的Gson。 但是Kotlin团队决定为Kotlin创建一个全新的本机序列化库。 问题是,为什么?
Serialization libraries like Moshi and Gson are Java libraries that use reflections, which is fine for Android development. Kotlin is not restricted to Android(JVM); it supports JavaScript(JS) and IOS(native) development. Reflections sure as hell won’t work with Kotlin.js and native modules. Moreover, using reflections in Android is also a downside.
诸如Moshi和Gson之类的序列化库是使用反射的Java库,这对于Android开发是很好的。 Kotlin不仅限于Android(JVM); 它支持JavaScript(JS)和IOS(本机)开发。 毫无疑问 ,反射不适用于Kotlin.js和本机模块。 此外,在Android中使用反射也是一个缺点。
Apart from multi-platform support and using reflections in serialization, there is one more drawback with Java serialization libraries: they won’t support default value variables in Kotlin. To understand it clearly, let’s start with a simple data class as shown below:
除了多平台支持和在序列化中使用反射之外,Java序列化库还有另一个缺点:它们在Kotlin中不支持默认值变量。 为了清楚地理解它,让我们从一个简单的数据类开始,如下所示:
data class SimpleExample(val data : String,var optionalData : String = "empty")
When we try to parse JSON with only data
node, then the optionalData
value is changed to null
instead of assigning a default value empty
as declared in the data class. This is a big problem because when a variable is declared without question mark, then the Kotlin compiler will guaranty that the variable is never going to be null
, but normal Java serialization libraries aren’t aware of that. This type of functionality conflict results in unexpected behavior of the app.
当我们尝试仅使用data
节点解析JSON时,则optionalData
值将更改为null
而不是将数据类中声明的默认值分配为empty
。 这是一个很大的问题,因为当声明一个没有问号的变量时,Kotlin编译器将保证该变量永远不会为null
,但是普通的Java序列化库并不知道这一点。 这种类型的功能冲突会导致应用程序发生意外行为。
So the Kotlin team decided to create a serialization library that works with all the platforms it’s supporting and is also without reflections.
因此,Kotlin团队决定创建一个序列化库,该库可与其支持的所有平台一起使用,并且也没有任何反思。
积分 (Integration)
To use the Kotlin serialization library, we have to integrate both a serialization plugin and a runtime serialization library. The serialization plugin generates the code to parse the JSON without using any reflections. On the other hand, the runtime library uses this code to serialize the data classes.
要使用Kotlin序列化库,我们必须集成一个序列化插件和一个运行时序列化库。 序列化插件生成代码以解析JSON,而无需使用任何反射。 另一方面,运行时库使用此代码来序列化数据类。
To integrate the serialization plugin, add the following line below all the plugins at the top of the app-level build.gradle
file.
要集成序列化插件,请在应用程序级别build.gradle
所有插件下方添加以下行。 文件。
apply plugin: 'kotlinx-serialization'
You also need to add the line below under the dependencies node in the project-level build.gradle
file:
您还需要在项目级build.gradle
文件的依赖项节点下添加以下行:
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
Then add the following library implementation line under the dependencies tag in the app-level build.gradle
file:
然后在应用程序级别的build.gradle
文件中的dependencies标记下添加以下库实现行:
implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0"
如何将Kotlin序列化与数据类一起使用 (How to Use Kotlin Serialization With Data Classes)
Serialization can be done quite quickly with this native library from the Kotlin team. We need to add @Serializable
annotation above the intended class. Have a look:
使用Kotlin团队的本机库,可以非常快速地完成序列化。 我们需要在预期的类之上添加@Serializable
注释。 看一看:
@Serializable
data class SimpleExample(val data : String,var optionalData : String = "empty")
That’s all; you don’t need to annotate every variable with serializable labels like you have to do with regular libraries. This is pretty straightforward. Now let’s see a bit more realistic example with Retrofit 2.
就这样; 您不需要像使用常规库那样用可序列化的标签注释每个变量。 这很简单。 现在,让我们看看Retrofit 2的更实际的示例。
带有Kotlinx序列化的翻新2 (Retrofit 2 With kotlinx-serialization)
We’re all familiar with retrofit adapters for RxJava, Coroutines, Moshi, and other libraries, right? Likewise, Kotlin serialization also has an adapter from JakeWharton through which we can link retrofit response with Kotlin serialization code.
我们都熟悉RxJava , Coroutines ,Moshi和其他库的改造适配器,对吗? 同样,Kotlin序列化还具有JakeWharton的适配器,我们可以通过该适配器将改造响应与Kotlin序列化代码链接。
To integrate this library into your project, add the line below under the dependencies
node in the app-level build.gradle
file:
要将此库集成到您的项目中,请在应用程序级build.gradle
文件的dependencies
节点下面添加以下行:
implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.5.0")
Now it’s time to link the adapter with the retrofit instance. Have a look at the code below:
现在是时候将适配器与改造实例链接起来了。 看下面的代码:
val contentType = "application/json".toMediaType()
val retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.addConverterFactory(serializationConverterFactory(contentType, JSON))
.build()
Assuming the result data class is annotated with the @Serializable
label, that’s all we need to do. The rest will be taken care of by the Kotlin Serialization Converter.
假设结果数据类带有@Serializable
标签,这就是我们需要做的。 其余的将由Kotlin序列化转换器处理。
隐藏功能 (Hidden Features)
编译时安全 (Compile-time safety)
This is for when you’re doing some complex serialization, like you’ve nested classes within the response data class. Have a look:
这是在执行一些复杂的序列化操作时使用的,例如您将类嵌套在响应数据类中。 看一看:
@Serializable
data class SimpleExample(val data : String,var optionalData : String = "empty",var complexClass: ComplexClass )
It’s good that you’ve annotated the SimpleExample
data class with @Serializable
, but what if you have forgotten to annotate ComplexClass
. Will that cause a crash at run time? Or you’ve check explicitly by yourself for whether every nested class is annotated or not?
最好用@Serializable
注释SimpleExample
数据类,但是如果忘记注释ComplexClass
。 这会在运行时导致崩溃吗? 还是您自己检查了每个嵌套类是否已被注释?
Relax; none of the above disasters will happen because Kotlin serialization library is compile-time safe, which means it shows an error if you haven’t annotated any of the nested classes with @Serializable
, no matter how deep the tree structure goes.
放松; 由于Kotlin序列化库是编译时安全的,因此不会发生上述任何灾难,这意味着如果您没有使用@ Serializable
注释任何嵌套类,则无论树结构有多深,它都将显示错误。
临时注释和可选注释 (Transient and optional annotations)
Transient: By annotating a variable in the data class as @Transient
, we’re indicating to the serializer to ignore this field completely.
瞬态:通过将数据类中的变量注释为@Transient
,我们指示序列化程序完全忽略此字段。
Optional: By annotating a variable in the data class as @Optional
, we’re indicating to the serializer that this variable is optional, so don’t break the process if you didn’t find it in the response. Also, we can assign a default value as shown below.
可选:通过将数据类中的变量注释为@Optional
,我们向序列化程序指示此变量是可选的,因此,如果您在响应中找不到该变量,请不要中断该过程。 另外,我们可以分配一个默认值,如下所示。
@Optional
var isOptional: Boolean = false
@Transient
var isTransient: Boolean = false
These two annotations make sense, and I don’t know how Java libraries missed them.
这两个注释很有意义,我不知道Java库是如何错过它们的。
奖金 (Bonus)
To learn more about Kotlin, read the previous parts of this Advanced Programming With Kotlin series:
要了解有关Kotlin的更多信息,请阅读“使用Kotlin进行高级编程”系列的先前部分:
To learn more about Kotlin Coroutines and other advanced features of Kotlin, read the following articles:
要了解有关Kotlin协程和Kotlin的其他高级功能的更多信息,请阅读以下文章:
Before we wrap up, I would like to thank Leonid Startsev. I’ve learned many of the concepts that I mentioned here from the talk that he gave at KotlinConfig 2019.
在总结之前,我要感谢Leonid Startsev。 从他在KotlinConfig 2019上的演讲中,我学到了我在这里提到的许多概念。
Thank you for reading.
感谢您的阅读。
序列化 数据库 持久化