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>