泛型接口的Kotlin序列化
尝试kotlin 1.4.32/serialization 1.1.0(和kotlin 1.5.0/serialization 1.2.0),我找不到序列化以下类层次结构的方法泛型接口的Kotlin序列化,kotlin,Kotlin,尝试kotlin 1.4.32/serialization 1.1.0(和kotlin 1.5.0/serialization 1.2.0),我找不到序列化以下类层次结构的方法 interface Range<T:Comparable<T>> @Serializable @SerialName("range") class SimpleRange<T:Comparable<T>>: Range<T> @Seria
interface Range<T:Comparable<T>>
@Serializable @SerialName("range")
class SimpleRange<T:Comparable<T>>: Range<T>
@Serializable @SerialName("multirange")
class MultiRange<T:Comparable<T>>: Range<T>
但我找不到一种方法来配置模块,使其能够序列化/反序列化单量程
或单量程
或多量程
或我可以在SerializerModule中声明的任何组合。
例如,如果我将
子类(SimpleRange.serializer(Int.serializer())
添加到上一个类中,对于没有泛型字段的伪类,我会得到一个SerializerReadyRegisteredException
,这就足够了:
val模块=序列化模块{
多态(范围::类){
子类(SimpleRange.serializer(多态序列化器(Comparable::class)))
子类(MultiRange.serializer(多态序列化器(Comparable::class)))
}
}
但是如果在这些类中有一个类型为T:Comparable
的字段,那么就比较棘手了。通常,您也需要为Comparable
接口声明多态序列化程序,但问题是您不能注册“基元类型”(String
,Int
,Double
,等等)作为多态序列化的子类(kotlinx.serialization的限制),这些类型在本例中是关键的
作为解决方法,您可以执行以下操作:
@ExperimentalSerializationApi
val module=SerializersModule{
上下文(Comparable::class){it[0]}//使用其第一个类型参数的序列化程序
}
T
类型的字段重新声明为Comparable
(在本例中基本相同,但在其他情况下,您将得到隐藏的错误消息java.lang.ArrayIndexOutOfBoundsException:索引0超出长度0的界限
),并用@context
注释标记它们:@Serializable
@序列名(“范围”)
类SimpleRange(@context-val-min:Comparable,@context-val-max:Comparable):范围
//由于丢失有关类型参数的信息,将无法工作
多态(范围::类){
子类(SimpleRange.serializer(ContextualSerializer(Comparable::class)))
子类(MultiRange.serializer(ContextualSerializer(Comparable::class)))
}
因此,为了保留类型参数信息,应通过具有具体类型参数的辅助函数手动选择子类序列化程序:
@Suppress(“未选中的\u CAST”)
内联序列化程序(值:T):KSerializer=when(值){
是SimpleRange->serializer()
是多范围->序列化程序()
else->throw NotImplementedError()//即使是密封接口KT-21908也仍然需要
}as系列化器
用法:
@ExperimentalSerializationApi
主要内容(){
val kotlinx=Json{
序列化模块=模块
}
val range1:SimpleRange=SimpleRange(1,2)
println(kotlinx.encodeToString(rangeSerializer(range1),range1))/{“min”:1,“max”:2}
val范围2:SimpleRange=SimpleRange(1.0,2.0)
println(kotlinx.encodeToString(rangeSerializer(range2),range2))/{“min”:1.0,“max”:2.0}
val范围3:范围=范围2
println(kotlinx.encodeToString(rangeSerializer(range3),range3))/{“min”:1.0,“max”:2.0}
}
更新
(反序列化)
由于我们在序列化此数据时放弃了多态序列化,因此在生成的JSON中没有字段来确定应该实例化Range
的哪个子类。但即使存在,也不够-我们还需要compariable
的类鉴别器
因此,我们需要一些启发式方法来实现
为了简化这些启发式操作,我建议为此添加专用字段:type
(可以配置属性)和comparableType
。因此,序列化程序应该进行调整:
@ExperimentalSerializationApi
内联有趣的序列化程序(值:T):序列化策略=
对象:序列化策略{
@抑制(“未选中的_CAST”)
private val rangeSerializer=when(值){
是SimpleRange->serializer()
是多范围->序列化程序()
else->throw NotImplementedError()//即使是密封接口KT-21908也仍然需要
}as系列化器
覆盖val描述符=rangeSerializer.descriptor
重写有趣的序列化(编码器:编码器,值:T)=使用(编码器作为JSONECODER){
val jsonElement=json.encodeToJsonElement(rangeSerializer,value)
encodeJsonElement(transformSerialize(jsonElement,json))
}
private fun transformSerialize(element:jsoneElement,json:json)=JsonObject(element.JsonObject.toMutableMap()。同样{
val typeSerialName=value::class.findAnnotation()?.value?:value::class.simpleName!!
it[json.configuration.classDiscriminator]=JsonPrimitive(typeSerialName)
it[“comparableType”]=JsonPrimitive(K::class.simpleName)
})
}
现在,可以声明尊敬的polymorhic反序列化程序:
@ExperimentalSerializationApi
@实验TDlibAPI
对象范围反序列化器:反序列化策略{
private val compariableserializers=buildMap{
registerSerializerFor()
registerSerializerFor()
registerSerializerFor()
}
@内部序列化API
override val descriptor=buildSerialDescriptor(“RangeDeserializer”,PolymorphicKind.SEALED)
override fun反序列化(解码器:解码器):Range=with(解码器作为JsonDecoder){
val jsonObject=decodeJsonEleme
polymorphic(Range::class) {
subclass(SimpleRange.serializer(Double.serializer()))
}
interface Range<T:Comparable<T>>
@Serializable @SerialName("range")
class SimpleRange<T:Comparable<T>>: Range<T> {//implementation}
@Serializable @SerialName("multirange")
class MultiRange<T:Comparable<T>>: Range<T> {//implementation}
val rangeModule = SerializersModule {
polymorphic(Comparable::class) {
subclass(Double.serializer())
subclass(Int.serializer())
}
polymorphic(Range::class) {
subclass(SimpleRange.serializer(PolymorphicSerializer(Comparable::class)))
subclass(MultiRange.serializer(PolymorphicSerializer(Comparable::class)))
}
}
// Build a range here
val range = ...
println(Json{
useArrayPolymorphism = true
serializersModule = (rangeModule)
}.encodeToString(range1))
["range",{"min":["kotlin.Double",10.0],"max":["kotlin.Double",20.0]}]