反序列化 json 以查找哪个对象映射 Android Kotlin
Deserialize a json to find which object maps Android Kotlin
在我的应用程序中,我使用 Sockets.The 来自套接字的收入消息是 json,我想将每个 json 映射到每个相应的对象。
例如我有 json
{ "er": { "i":"1001", "m":"message text" } }
匹配数据class
data class Error(
val er: Er
)
data class Er(
val i: String,
val m: String
)
但我也有一个json喜欢
{
"statusCode":200, "body":{
"au":{
"a": 44,
}
}
}
这是数据class
data class Authentication(
val body: Body,
val statusCode: Int
)
data class Body(
val au: Au
)
data class Au(
val a: Int
)
默认情况下,我知道我的 API 永远不会有相同类型的 json!
所以我尝试做类似
的事情
try {
val thing = Gson().fromJson(mJson, Error::class.java)
// This json is Error type of object. Do something with it
catch(e: JsonSyntaxException) {
// This json is not Error object. Maybe its Authentication
// Proceed to check another object
}
但是我注意到没有异常发生并且 thing
是一个具有空字段的 Error
对象。
是否有任何机制或库可以找到 json 映射到哪个对象?
您可以使用 kotlinx.serialization 库实现此目的。
但首先您需要将可能的反序列化类型集缩小到多态 class 层次结构。
在大多数情况下,它可能是一个接口:
interface AuthOrError
可能是反序列化结果的所有类型都应该实现它;并且所有涉及反序列化的classes都应该标上@Serializable
注解:
@Serializable
data class Authentication(val body: Body, val statusCode: Int) : AuthOrError
@Serializable
data class Body(val au: Au)
@Serializable
data class Au(val a: Int)
@Serializable
data class Error(val er: Er) : AuthOrError
@Serializable
data class Er(val i: String, val m: String)
但是反序列化库不是通灵的。 JSON内容应该有一些独特的区别特征,以便反序列化库可以将其映射到特定类型。
实现它的最简单方法 - 是将带有目标类型值 FQN 的 type
字段添加到每个 JSON 对象(如 {"type": "Error", "er": { "i":"1001", "m":"message text" } })
。之后你需要注册所有此字段的可能值(一组精确的类型,实现此接口,可能是反序列化结果):
val authOrErrorModule = SerializersModule {
polymorphic(AuthOrError::class) {
subclass(Authentication::class)
subclass(Error::class)
}
}
然后将其传递给 serializersModule
属性 奇迹发生了:
when (val thing = Json{serializersModule = authOrErrorModule}.decodeFromString<AuthOrError>(mJson)) {
is Authentication -> {
println(thing.statusCode) //smart casted as Authentication
}
is Error -> {
println(thing.er) //smart casted as Error
}
}
如果无法修改 JSON 格式,则需要创建自己的反序列化器并根据 JSON 内容手动定义用于选择类型(更准确地说,其(反)序列化器)的算法.例如,在这种情况下,您可以说“如果 JSON 有 statusCode
字段,那么它必须是 Authentication
,否则它是 Error
”:
object AuthOrErrorSerializer : JsonContentPolymorphicSerializer<AuthOrError>(AuthOrError::class) {
override fun selectDeserializer(element: JsonElement) = when {
"statusCode" in element.jsonObject -> Authentication.serializer()
else -> Error.serializer()
}
}
然后将其作为序列化程序传递,瞧:
when (val thing = Json.decodeFromString(AuthOrErrorSerializer, mJson)) {
is Authentication -> {
println(thing.statusCode)// smart casted as Authentication
}
is Error -> {
println(thing.er) // smart casted as Error
}
}
在我的应用程序中,我使用 Sockets.The 来自套接字的收入消息是 json,我想将每个 json 映射到每个相应的对象。
例如我有 json
{ "er": { "i":"1001", "m":"message text" } }
匹配数据class
data class Error(
val er: Er
)
data class Er(
val i: String,
val m: String
)
但我也有一个json喜欢
{
"statusCode":200, "body":{
"au":{
"a": 44,
}
}
}
这是数据class
data class Authentication(
val body: Body,
val statusCode: Int
)
data class Body(
val au: Au
)
data class Au(
val a: Int
)
默认情况下,我知道我的 API 永远不会有相同类型的 json!
所以我尝试做类似
的事情try {
val thing = Gson().fromJson(mJson, Error::class.java)
// This json is Error type of object. Do something with it
catch(e: JsonSyntaxException) {
// This json is not Error object. Maybe its Authentication
// Proceed to check another object
}
但是我注意到没有异常发生并且 thing
是一个具有空字段的 Error
对象。
是否有任何机制或库可以找到 json 映射到哪个对象?
您可以使用 kotlinx.serialization 库实现此目的。 但首先您需要将可能的反序列化类型集缩小到多态 class 层次结构。 在大多数情况下,它可能是一个接口:
interface AuthOrError
可能是反序列化结果的所有类型都应该实现它;并且所有涉及反序列化的classes都应该标上@Serializable
注解:
@Serializable
data class Authentication(val body: Body, val statusCode: Int) : AuthOrError
@Serializable
data class Body(val au: Au)
@Serializable
data class Au(val a: Int)
@Serializable
data class Error(val er: Er) : AuthOrError
@Serializable
data class Er(val i: String, val m: String)
但是反序列化库不是通灵的。 JSON内容应该有一些独特的区别特征,以便反序列化库可以将其映射到特定类型。
实现它的最简单方法 - 是将带有目标类型值 FQN 的 type
字段添加到每个 JSON 对象(如 {"type": "Error", "er": { "i":"1001", "m":"message text" } })
。之后你需要注册所有此字段的可能值(一组精确的类型,实现此接口,可能是反序列化结果):
val authOrErrorModule = SerializersModule {
polymorphic(AuthOrError::class) {
subclass(Authentication::class)
subclass(Error::class)
}
}
然后将其传递给 serializersModule
属性 奇迹发生了:
when (val thing = Json{serializersModule = authOrErrorModule}.decodeFromString<AuthOrError>(mJson)) {
is Authentication -> {
println(thing.statusCode) //smart casted as Authentication
}
is Error -> {
println(thing.er) //smart casted as Error
}
}
如果无法修改 JSON 格式,则需要创建自己的反序列化器并根据 JSON 内容手动定义用于选择类型(更准确地说,其(反)序列化器)的算法.例如,在这种情况下,您可以说“如果 JSON 有 statusCode
字段,那么它必须是 Authentication
,否则它是 Error
”:
object AuthOrErrorSerializer : JsonContentPolymorphicSerializer<AuthOrError>(AuthOrError::class) {
override fun selectDeserializer(element: JsonElement) = when {
"statusCode" in element.jsonObject -> Authentication.serializer()
else -> Error.serializer()
}
}
然后将其作为序列化程序传递,瞧:
when (val thing = Json.decodeFromString(AuthOrErrorSerializer, mJson)) {
is Authentication -> {
println(thing.statusCode)// smart casted as Authentication
}
is Error -> {
println(thing.er) // smart casted as Error
}
}