首先请注意,Kotlin序列化是围绕仅在编译时定义的序列化器设计的,因为这提供了"类型安全,性能和避免反射使用"1.这就是为什么这个框架是围绕着序列化器的类定义的.
记住这一点,有两种方法可以解决向序列化程序提供参数的问题:
- 在带有零参数构造函数的类中定义序列化程序,该构造函数静态地接收依赖项(这里是
ThingRepository
);或者
- 使用contextual serialization,这是用于编译时未定义的序列化程序的功能.
1. Providing the dependency statically
使用这种方法,您可以使用静态字段来编写序列化器,即:
class ThingSerializer : KSerializer<Thing> {
companion object {
var thingRepository: ThingRepository? = null
}
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("Thing", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: Thing) {
encoder.encodeString(value.id)
}
override fun deserialize(decoder: Decoder): Thing {
val id = decoder.decodeString()
return thingRepository!!.findById(id)!!
}
}
您可以通过注释目标类来告知插件有关序列化程序的信息:
@Serializable(with = ThingSerializer::class)
data class Thing
您还必须在序列化之前设置静态字段:
ThingSerializer.thingRepository = thingRepository
2. Contextual serialization
这种方法允许您在序列化器模块中注册一个序列化器实例,而不是附加一个类,如下所示:
val serializersModule = SerializersModule {
contextual(ThingSerializer(thingRepository))
}
您还需要在编译时告诉插件您想要为该类使用上下文序列化程序.有几种方法可以做到这一点,具体取决于你的品味:
- 注释原始类
这是可行的,但编译器会发出警告,因为您正在对特定类使用类型Any
的序列化程序.因此,有必要取消该警告:
@Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
@OptIn(ExperimentalSerializationApi::class)
@Serializable(with = ContextualSerializer::class)
data class Thing
- 为每种用法加
@Contextual
个注解
如果您不希望隐藏警告,则可以在每次出现目标类时使用@Contextual
对其进行注释.当然,这样做的缺点是您必须在任何地方都包含该注释.
@Serializable
class ThingUser(@Contextual private val thing: Thing)
- 用
@UseContextualSerialization
注释每个文件的用法
您还可以使用文件级注释:
@file:UseContextualSerialization(Thing::class)
package com.thing
class ThingUserTwo(private val thing: Thing)
最后,您必须记住在创建Json
个实例(或等效实例)时提供序列化程序模块:
val json = Json { serializersModule = serializersModule }
1请参阅serialization KEEP.大概框架在执行代码生成时在编译时实例化序列化程序.