Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/kotlin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
泛型接口的Kotlin序列化_Kotlin - Fatal编程技术网

泛型接口的Kotlin序列化

泛型接口的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

尝试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>

@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的限制),这些类型在本例中是关键的

作为解决方法,您可以执行以下操作:

  • 使用kotlinx.serialization 1.2.0,它允许为泛型类声明上下文序列化程序,因此您的模块应为:
  • @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):范围
    
  • 不幸的是,无法在serializers模块中直接为泛型类组合多态序列化程序和上下文序列化程序:
  • //由于丢失有关类型参数的信息,将无法工作
    多态(范围::类){
    子类(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]}]