mis*_*iac 12 json kotlin moshi
有没有办法反序列化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
Run Code Online (Sandbox Code Playgroud)
LayerType只是一些枚举,可用于区分此对象应具有的类型.
我以为我可以这样添加适配器:
class LayerAdapter{
@FromJson
fun fromJson(layerJson: LayerJson): Layer {
return when (layerJson.layerType) {
LayerType.SHAPE -> PreCompLayer()
LayerType.SOLID -> SolidLayer()
LayerType.Text -> TextLayer()
}
}
}
Run Code Online (Sandbox Code Playgroud)
其中LayerJson将是具有所有LayerTypes的所有可能字段的对象.
现在的问题是:
无法序列化抽象类com.example.models.layers.Layer
我可以尝试使用接口,但我不认为在这里使用空接口是正确的.
Bak*_*aii 14
是的,您可以创建一个自定义类型适配器来解析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")
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,我必须做出清晰一些改变,你的数据类(一个额外的属性到每一个的Layer类型,例如shape用于ShapeLayer):
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
}
Run Code Online (Sandbox Code Playgroud)
测试代码:
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)
Run Code Online (Sandbox Code Playgroud)
输出:
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"}]
Run Code Online (Sandbox Code Playgroud)
编辑:当您尝试解析包含的其他对象时,可以照常添加适配器Layer.假设你有一个像这样的对象:
data class LayerContainer(val layers: List<Layer>)
Run Code Online (Sandbox Code Playgroud)
测试代码:
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)
Run Code Online (Sandbox Code Playgroud)
事实证明,我的代码实际上从一开始就是正确的!
问题出在数据类内的字段声明:
data class LayerContainer(var/val layers: List<Layer>)
Run Code Online (Sandbox Code Playgroud)
它适用于 val,不适用于 var!Kotlin 以某种方式在下面创建了不同的代码。这是我模型这部分的最终代码:
@JvmSuppressWildcards var layers: List<Layer>
Run Code Online (Sandbox Code Playgroud)