如何序列化以下数据?这是
AppConfig
,value 的值可以是任何类型,我不能使用 Any 进行序列化。
[
{
"key": "PROFILE_PHOTO",
"value": "url"
},
{
"key": "RELATIONSHIP",
"value": 0.6
},
{
"key": "SEX",
"value": [ "Man", "Woman"]
},
{
"key": "IOS_VER",
"value": 5
}
]
简短的答案是:具有多态性。我们需要不同的类型来表示可以接收的不同类型的对象。
在很大程度上,类型的选择取决于对象的含义和用途,而不仅仅是像我们这里一样查看原始数据。
但是,我们可以根据您提供的内容猜测合适的类型。
现在我们要编写一个密封类层次结构来表示传入的对象,因为这使得多态序列化变得简单(docs):
@Serializable
@JsonClassDiscriminator("key")
sealed class ApiObject
@Serializable @SerialName("PROFILE_PHOTO")
data class ProfilePhoto(@SerialName("value") val url: String) : ApiObject()
@Serializable @SerialName("RELATIONSHIP")
data class Relationship(@SerialName("value") val coefficient: Double) : ApiObject()
@Serializable @SerialName("SEX")
data class Sex(@SerialName("value") val sexes: List<SexType>) : ApiObject()
@Serializable @SerialName("IOS_VER")
data class IosVersion(@SerialName("value") val versionNumber: Int) : ApiObject()
enum class SexType { Man, Woman }
我们还使用了该库的一些功能来为我们提供更可用的类层次结构。特别是:
我们已经为我们可以从 API 接收的每种可能的消息类型指定了名称,并且我们使用
SerialName
注释为传入的“值”字段提供了有意义的名称。
“关键”字段将用作我们的“鉴别器”,它告诉库要选择哪一个类。默认情况下,这是“type”字段,因此我们需要告诉库使用“key”而不是
JsonClassDiscriminator
注释。
最后,因为“关键”字段是在 screaming Snake case 中给出的,所以我们需要使用
SerialName
注解来调整类的序列化名称,以便我们的类名称能够符合习惯的 Kotlin 实践。
现在我们准备好测试我们的代码了:
val testMessage: String = """
[
{
"key": "PROFILE_PHOTO",
"value": "url"
},
{
"key": "RELATIONSHIP",
"value": 0.6
},
{
"key": "SEX",
"value": [ "Man", "Woman"]
},
{
"key": "IOS_VER",
"value": 5
}
]
"""
val deserializedMessage: List<ApiObject> = Json.decodeFromString(testMessage)
val expectedDeserializedMessage = listOf(
ProfilePhoto("url"),
Relationship(0.6),
Sex(listOf(SexType.Man, SexType.Woman)),
IosVersion(5)
)
println("Does our code work? ${expectedDeserializedMessage == deserializedMessage}")