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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.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
Json 如何序列化/反序列化Kotlin密封类?_Json_Kotlin_Singleton_Deserialization_Genson - Fatal编程技术网

Json 如何序列化/反序列化Kotlin密封类?

Json 如何序列化/反序列化Kotlin密封类?,json,kotlin,singleton,deserialization,genson,Json,Kotlin,Singleton,Deserialization,Genson,我有一个密封的类: sealed class ViewModel { data class Loaded(val value : String) : ViewModel() object Loading : ViewModel() } import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxm

我有一个密封的类:

sealed class ViewModel {

  data class Loaded(val value : String) : ViewModel()
  object Loading : ViewModel()

}
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.module.SimpleModule

sealed class ViewModel {
    data class Loaded(val value: String) : ViewModel()
    object Loading : ViewModel()
}

// Custom serializer
class ViewModelDeserializer : JsonDeserializer<ViewModel>() {
    override fun deserialize(jp: JsonParser?, p1: DeserializationContext?): ViewModel {
        val node: JsonNode? = jp?.getCodec()?.readTree(jp)
        val value = node?.get("value")
        return if (value != null) ViewModel.Loaded(value.asText()) else ViewModel.Loading
    }
}

fun main(args: Array<String>) {
    val m = createCustomMapper()
    val ser1 = m.writeValueAsString(ViewModel.Loading)
    println(ser1)
    val ser2 = m.writeValueAsString(ViewModel.Loaded("test"))
    println(ser2)
    val deserialized1 = m.readValue(ser1, ViewModel::class.java)
    val deserialized2 = m.readValue(ser2, ViewModel::class.java)
    println(deserialized1)
    println(deserialized2)
}

// Using mapper with custom serializer
private fun createCustomMapper(): ObjectMapper {
    val m = ObjectMapper()
    val sm = SimpleModule()
    sm.addDeserializer(ViewModel::class.java, ViewModelDeserializer())
    m.registerModule(sm)
    return m
}
sealed class Parent(val name: String) {

    private companion object {
        @JsonCreator
        @JvmStatic
        fun findBySimpleClassName(simpleName: String): Parent? {
            return Parent::class.sealedSubclasses.first {
                it.simpleName == simpleName
            }.objectInstance
        }
    }
}
我如何序列化/反序列化ViewModel类的实例,比如从JSON格式到JSON格式

我尝试使用Genson序列化器/反序列化器库-它可以处理Kotlin数据类,也可以支持多态类型(例如,使用一些元数据指定具体类型)


但是,库在Kotlin
对象
类型上失败,因为这些类型是没有公共构造函数的单例。我想我可以编写一个定制的Genson转换器来处理它,但也许有一个更简单的方法来处理它?

关于创建定制序列化程序,您可能是对的

我已经尝试使用库和Kotlin对您的类进行序列化和反序列化

以下是Jackson的Maven依赖项:

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.8.8</version>
</dependency>

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.8.8</version>
</dependency>

我最终实现了一个定制的转换器加上一个工厂,以正确地将其插入Genson

它使用Genson的元数据约定将对象表示为:

{ 
  "@class": "com.example.ViewModel.Loading" 
}
转换器假定设置了useClassMetadata标志,因此序列化只需要标记一个空对象。对于反序列化,它从元数据解析类名,加载它并获取objectInstance

object KotlinObjectConverter : Converter<Any> {

override fun serialize(objectData: Any, writer: ObjectWriter, ctx: Context) {
    with(writer) {
        // just empty JSON object, class name will be automatically added as metadata
        beginObject()
        endObject()
    }
}

override fun deserialize(reader: ObjectReader, ctx: Context): Any? =
    Class.forName(reader.nextObjectMetadata().metadata("class"))
        .kotlin.objectInstance
        .also { reader.endObject() }
}

使用链式转换器功能的代码可能会更好,但我还没有时间查看它。

最近我遇到了类似的问题(尽管使用的是Jackson,而不是Genson)

假设我具备以下条件:

sealed class Parent(val name: String)

object ChildOne : Parent("ValOne")
object ChildTwo : Parent("ValTwo")

然后将
JsonCreator
函数添加到密封类:

sealed class ViewModel {

  data class Loaded(val value : String) : ViewModel()
  object Loading : ViewModel()

}
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.module.SimpleModule

sealed class ViewModel {
    data class Loaded(val value: String) : ViewModel()
    object Loading : ViewModel()
}

// Custom serializer
class ViewModelDeserializer : JsonDeserializer<ViewModel>() {
    override fun deserialize(jp: JsonParser?, p1: DeserializationContext?): ViewModel {
        val node: JsonNode? = jp?.getCodec()?.readTree(jp)
        val value = node?.get("value")
        return if (value != null) ViewModel.Loaded(value.asText()) else ViewModel.Loading
    }
}

fun main(args: Array<String>) {
    val m = createCustomMapper()
    val ser1 = m.writeValueAsString(ViewModel.Loading)
    println(ser1)
    val ser2 = m.writeValueAsString(ViewModel.Loaded("test"))
    println(ser2)
    val deserialized1 = m.readValue(ser1, ViewModel::class.java)
    val deserialized2 = m.readValue(ser2, ViewModel::class.java)
    println(deserialized1)
    println(deserialized2)
}

// Using mapper with custom serializer
private fun createCustomMapper(): ObjectMapper {
    val m = ObjectMapper()
    val sm = SimpleModule()
    sm.addDeserializer(ViewModel::class.java, ViewModelDeserializer())
    m.registerModule(sm)
    return m
}
sealed class Parent(val name: String) {

    private companion object {
        @JsonCreator
        @JvmStatic
        fun findBySimpleClassName(simpleName: String): Parent? {
            return Parent::class.sealedSubclasses.first {
                it.simpleName == simpleName
            }.objectInstance
        }
    }
}

现在,您可以在json属性中使用
ChildOne
ChildTwo
作为
key
进行反序列化。

为什么要尝试反序列化singleton?@jrtapsell-因为它不包含任何数据,所以不需要有多个此类实例。使它成为一个常规类是一个解决方法,但它需要equals/hashcode重写,通常感觉不太对。谢谢你的回答。我知道定制序列化程序可以解决这个问题(我甚至认为它可以是一个通用的转换器,而不是绑定到特定的
对象
类型)。然而,我想知道是否有现成的解决方案:)@ZbigniewMalinowski我曾试图与Jackson一起找到现成的解决方案,但没有成功——可能有一个更聪明的库(或编码器)。这是目前最好的解决方案。但我猜它不会处理嵌套的密封类?@CarsonHolzheimer我还没有尝试过它,我不明白为什么它不会处理嵌套的密封类。我一定是缺少一些基本的东西。我可以使用这种方法序列化密封类实例,但使用jackson对象映射器反序列化字符串时遇到问题:“无法从对象值反序列化(没有基于委托或属性的创建者)”。你能提供一个将字符串反序列化为对象实例的例子吗?我想我已经没有了,但我会尝试查找它,并更新答案@BastianStein。也许你可以打开另一个问题,在那里发布你的代码。更容易看出你是否遗漏了什么