12

得到一个混合了普通字符串和图像对象的 json 列表,如下所示:

 {
  "mixList": [
    "string",
    {
      "imageUrl": "http://...",
      "height": 320,
      "width": 480
    }
  ]
}

如何用 Moshi 解析?

我希望有一个List<Data>, whereStringData extends DataImageData extends Data

4

1 回答 1

6

I've solved this problem using Moshi with a CustomAdaptor. After a lot of research I wasn't able to find a better "out-of-the-box" solution. This solutions is in kotlin but can easily be ported to Java as well.

First let's define the types we are trying to parse here. I'll call the wrapper type, that contains the mixList, Response:

@JsonClass(generateAdapter = true)
data class Response(val mix_types: Data)

And the 2 different types that can be inside the list StringData and ImageData:

sealed class Data {
    data class StringData(val value: String) : Data()

    @JsonClass(generateAdapter = true)
    data class ImageData(
        val imageUrl: String,
        val height: Int,
        val width: Int
    ) : Data()
}

As I'm using Moshi code-gen, so I have annotated Response and ImageData with @JsonClass(generateAdapter = true) so that Moshi will generate the adapters for these types(and I'll leverage this in my custom adapter).

I want to provide my own custom adapter to the Data type, and I won't also want the adapter Moshi would generate for the StringData type, since this is precisely what I want to serialise/deserialise into a String, so I won't annotate these classes.

Now I'm gonna write my custom adapter like this:

class DataCustomAdapter {
    @FromJson
    fun fromJson(jsonReader: JsonReader, delegate: JsonAdapter<ImageData>): Data? {
        return if (jsonReader.peek() == BEGIN_OBJECT) {
            delegate.fromJson(jsonReader)
        } else {
            StringData(jsonReader.nextString())
        }
    }

    @ToJson
    fun toJson(jsonWriter: JsonWriter, data: Data, delegate: JsonAdapter<ImageData>) {
        when (data) {
            is ImageData -> delegate.toJson(jsonWriter, data)
            is StringData -> jsonWriter.value(data.value)
        }
    }
}

all it's missing now is to register the custom adapter with Moshi:

private val moshi = Moshi.Builder()
    .add(DataCustomAdapter())
    .build()
于 2020-12-02T10:38:58.967 回答