Android:使用Moshi适配器解析内部非结构化Json

时间:2019-07-14 05:11:38

标签: android json gson retrofit moshi

我很难解析JSON(与Moshi)的某些内部部分,这些部分可能相差很大,并且高度非结构化。总体看起来像这样:

response: {
    items: [{
        type: "typeA",
        data: {
            "1563050214700-001": {
                foo: 123 ....
            }
        }
    }, {
        type: "typeB",
        data: {
            "1563050214700-002": {[
                // differs a lot from previous one
                {bar: 123 .... }
            ]}
        }
    }]
}

数据类结构如下:

data class Response(
    val items: Map<String,List<Item?>>?
) {
    data class Item(
        val type: String?,
        val data: Map<String,List<DataItem?>>?
    ) {
        data class DataItem(
            // members highly unstructured
        )
    }
}

“ DataItem”的架构变化很大。看起来Moshi codegen支持适配器,该适配器可能潜在地允许手动解析这些内部数据类,但是我找不到正确的教程或示例。理想情况下,我希望将整个Response解析为好像是定义良好的JSON。

这是我使用翻新/ moshi的方式

@Provides
@Singleton
@MyApp
fun provideMyAppRetrofit(context: Context, @MyApp okHttpClient: OkHttpClient): Retrofit {
    return Retrofit.Builder()
        .client(okHttpClient)
        .addConverterFactory(MoshiConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .baseUrl(context.getString(R.string.APP_BASE_URL))
        .build()
}

@Provides
@Singleton
fun provideMyAppApiService(@MyApp retrofit: Retrofit): MyAppApiService {
    return retrofit.create(MyAppApiService::class.java)
}

我该如何实现?任何示例或参考实现都会有所帮助。

2 个答案:

答案 0 :(得分:1)

欢迎使用多态JSON解析问题一词!

我们正在编写自己的JSON适配器,如下所示:

internal class CardJsonAdapter(
        moshi: Moshi
) : JsonAdapter<Card>() {

    private val cardTypeAdapter = moshi.adapter(Card.Type::class.java)
    private val amountsWithActionAdapter = moshi.adapter(AmountsWithActionCard::class.java)
    private val backgroundImageCardAdapter = moshi.adapter(BackgroundImageCard::class.java)

    @Suppress("TooGenericExceptionCaught")
    override fun fromJson(reader: JsonReader): Card = try {

        @Suppress("UNCHECKED_CAST")
        val jsonMap = reader.readJsonValue() as Map<String, Any?>
        val type = cardTypeAdapter.fromJsonValue(jsonMap["type"])
        createCardWithType(type, jsonMap)

    } catch (error: Exception) {
        if (BuildConfig.DEBUG) {
            Log.w("CardJsonAdapter", "Failed to parse card", error)
        }
        // Try not to break the app if we get unexpected data: ignore errors and return a placeholder card instead.
        UnknownCard
    }

    override fun toJson(writer: JsonWriter, value: Card?) {
        throw NotImplementedError("This adapter cannot write cards to JSON")
    }

    private fun createCardWithType(type: Type?, jsonMap: Map<String, Any?>) = when (type) {
        null -> UnknownCard
        Type.AMOUNTS_WITH_ACTION -> amountsWithActionAdapter.fromJsonValue(jsonMap)!!
        Type.BACKGROUND_IMAGE_WITH_TITLE_AND_MESSAGE -> backgroundImageCardAdapter.fromJsonValue(jsonMap)!!
    }
}

但是,它不再是必需的。 Moshi现在支持多态JSON解析-https://proandroiddev.com/moshi-polymorphic-adapter-is-d25deebbd7c5

答案 1 :(得分:0)

制作自定义适配器

class YourAdapter {

@FromJson
fun fromJson(reader: JsonReader, itemsAdapter: JsonAdapter<ItemsResponse>): List<ItemsResponse>? {
    val list = ArrayList<ItemsResponse>()
    if (reader.hasNext()) {
        val token = reader.peek()
        if (token == JsonReader.Token.BEGIN_ARRAY) {
            reader.beginArray()
            while (reader.hasNext()) {
                val itemResponse = itemsAdapter.fromJsonValue(reader.readJsonValue())
                itemsResponse?.let {
                    list.add(itemResponse)
                }
            }
            reader.endArray()
        }
    }
    return list
}
}