2017-09-21 9 views
5

모시 + 코 틀린 + 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 

LayerType를 사용하여 역 직렬화 된 JSON의 방법은이 객체가 있어야한다 유형을 구분하는 데 사용할 수 있습니다 그냥 몇 가지 열거 거기입니다. 모든 LayerTypes 가능한 모든 필드가

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

LayerJson이 될 것 개체 :

은 내가 어댑터이 방법을 추가 할 수 있습니다 생각했다.

지금 문제는 다음과 같습니다

추상 클래스 com.example.models.layers.Layer를 직렬화 할 수 없습니다

I 인터페이스를 사용하려고 할 수 있지만, 나는 그것이있을 거라고 생각하지 않습니다 이 경우 빈 인터페이스를 사용하도록 수정하십시오.

+0

'@ ToJson' 메서드가 누락되었다고 생각합니까? 아래의 답변은 정확합니다. –

+0

@ToJson이 없습니다. 예를 들어 – miszmaniac

+0

흠에 대해 중요하지 않다고 생각했던 코드는 모두 건너 뛰었습니다.이 코드는 대답과 동일하게 보입니다. 그걸 작동 시켰 니? –

답변

0

그것은 내 코드는 처음부터 실제로 정확하다고 밝혀졌다!

문제는 데이터 클래스의 내부 필드 선언했다 :

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

그것은 발에 작동하고, VAR 작동하지 않습니다! 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은 다음과 같습니다. { "layers" : [... 목록 ...]} 이 유형 지정 목록 어댑터를 빌더에 연결하는 방법을 모르겠습니까? – miszmaniac

+0

@miszmaniac이 사례에 대한 답변을 업데이트했습니다. – BakaWaii