Moshi + Kotlin + SealedClass

有没有反序列化json使用的方法

sealed class Layer data class ShapeLayer(var type: LayerType) : Layer data class TextLayer(var type: LayerType) : Layer data class ImageLayer(var type: LayerType) : Layer 

LayerType只是一些枚举,可以用来区分这个对象应该具有哪种类型。

我想我可以这样添加Adapter:

 class LayerAdapter{ @FromJson fun fromJson(layerJson: LayerJson): Layer { return when (layerJson.layerType) { LayerType.SHAPE -> PreCompLayer() LayerType.SOLID -> SolidLayer() LayerType.Text -> TextLayer() } } } 

其中LayerJson将是所有LayerType的每个可能字段的对象。

现在的问题是:

无法序列化抽象类com.example.models.layers.Layer

我可以尝试使用接口,但是我不认为在这里使用空接口是正确的。

是的,你可以创建一个自定义类型的适配器来解析json根据layerType像这样:

 class LayerAdapter { @FromJson fun fromJson(layerJson: LayerJson): Layer = when (layerJson.layerType) { LayerType.SHAPE -> ShapeLayer(layerJson.layerType, layerJson.shape ?: "") LayerType.TEXT -> TextLayer(layerJson.layerType, layerJson.text ?: "") LayerType.IMAGE -> ImageLayer(layerJson.layerType, layerJson.image ?: "") } @ToJson fun toJson(layer: Layer): LayerJson = when (layer) { is ShapeLayer -> LayerJson(layer.type, shape = layer.shape) is TextLayer -> LayerJson(layer.type, text = layer.text) is ImageLayer -> LayerJson(layer.type, image = layer.image) else -> throw RuntimeException("Not support data type") } } 

在这里,我已经对数据类进行了一些更改(为每个Layer类型额外的属性,例如ShapeLayer shape ):

 sealed class Layer data class ShapeLayer(val type: LayerType, val shape: String) : Layer() data class TextLayer(val type: LayerType, val text: String) : Layer() data class ImageLayer(val type: LayerType, val image: String) : Layer() //LayerJson contains every possible property of all layers data class LayerJson(val layerType: LayerType, val shape: String? = null, val text: String? = null, val image: String? = null) : Layer() enum class LayerType { SHAPE, TEXT, IMAGE } 

测试代码:

 val moshi = Moshi.Builder() .add(LayerAdapter()) .build() val type = Types.newParameterizedType(List::class.java, Layer::class.java) val adapter = moshi.adapter<List<Layer>>(type) //Convert from json string to List<Layer> val layers: List<Layer>? = adapter.fromJson(""" [ {"layerType":"SHAPE", "shape":"I am rectangle"}, {"layerType":"TEXT", "text":"I am text"}, {"layerType":"IMAGE", "image":"I am image"} ] """.trimIndent()) layers?.forEach(::println) //Convert a list back to json string val jsonString: String = adapter.toJson(layers) println(jsonString) 

输出:

 ShapeLayer(type=SHAPE, shape=I am rectangle) TextLayer(type=TEXT, text=I am text) ImageLayer(type=IMAGE, image=I am image) [{"layerType":"SHAPE","shape":"I am rectangle"},{"layerType":"TEXT","text":"I am text"},{"image":"I am image","layerType":"IMAGE"}] 

编辑:您可以照常添加适配器,当您试图解析包含Layer其他对象。 假设你有这样一个对象:

 data class LayerContainer(val layers: List<Layer>) 

测试代码:

 val moshi = Moshi.Builder() .add(LayerAdapter()) .build() val adapter = moshi.adapter(LayerContainer::class.java) val layerContainer: LayerContainer? = adapter.fromJson(""" { "layers": [ {"layerType":"SHAPE", "shape":"I am rectangle"}, {"layerType":"TEXT", "text":"I am text"}, {"layerType":"IMAGE", "image":"I am image"} ] } """.trimIndent()) layerContainer?.layers?.forEach(::println) val jsonString: String = adapter.toJson(layerContainer) println(jsonString) 

事实证明,我的代码从一开始就是正确的!

问题是数据类中的字段声明:

 data class LayerContainer(var/val layers: List<Layer>) 

它与val一起工作,不能和var一起工作! Kotlin以某​​种方式在下面创建不同的代码。 这是我对这部分模型的最终代码:

 @JvmSuppressWildcards var layers: List<Layer>