2017-09-21 2 views
5

モシ+ Kotlin + SealedClass

sealed class Layer 

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

を使用してJSONをデシリアライズする方法はありますLayerTypeは、このオブジェクトが持つべきどのタイプの識別に使用することができるだけでいくつか列挙型です。

私は、アダプタをこのように追加できると思っていた:

LayerJsonはすべてLayerTypesの可能なすべてのフィールドを持つオブジェクトになり
class LayerAdapter{ 
    @FromJson 
    fun fromJson(layerJson: LayerJson): Layer { 
     return when (layerJson.layerType) { 
      LayerType.SHAPE -> PreCompLayer() 
      LayerType.SOLID -> SolidLayer() 
      LayerType.Text -> TextLayer() 
     } 
    } 
} 

は、今の問題は、次のとおりです。

抽象クラスcom.example.models.layers.Layerにシリアライズすることはできません

私はインターフェイスを使用しようとすることができますが、私はそれがあるとは思いませんこれで空のインターフェースを使用するように修正してください。

+0

「@ ToJson」メソッドが欠落していると思いますか?以下の答えは正しいです。 –

+0

@ToJsonはありません、私はちょうど – miszmaniac

+0

hmのために重要ではないと思ったコードをすべてスキップしました。そして、これは答えと同じように見えます。あなたはそれを働かせましたか? –

答えて

0

は、それは私のコードは、最初から実際に正しかったことが判明!それはヴァルで動作し、VARでは動作しません

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

問題は、データクラス内のフィールド宣言していました! Kotlinは何とか下に別のコードを作成します。 これはモデルのこの部分の最終コードです

@JvmSuppressWildcards var layers: List<Layer> 
4

はい、あなたはこのようなlayerTypeによるJSONを解析するためのカスタムタイプのアダプタを作成することができます

ここ
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) 
+4

偉大な答え。これが大好き。 –

+0

OMGこれは網羅的な答えです:)ありがとうございました! 悲しいことに、それは私にとってはうまくいきません:) jsonのルートにレイヤー配列を作るためにjsonを展開しましたが、実際には動作しますが、問題はどこか他の場所にあります: 私のjsonは次のようになります: { :[...リスト...]} このタイプ付きリストアダプターをビルダーに接続する方法がわかりません。 – miszmaniac

+0

@miszmaniac私はこの場合の答えを更新しました。 – BakaWaii