Android:使用 Moshi 适配器解析内部非结构化 Json
Android: Parse inner unstructured Json with Moshi adapters
我无法解析 JSON(使用 Moshi)的某些内部部分,这些部分可能变化很大且高度非结构化。整体看起来像:
response: {
items: [{
type: "typeA",
data: {
"1563050214700-001": {
foo: 123 ....
}
}
}, {
type: "typeB",
data: {
"1563050214700-002": {[
// differs a lot from previous one
{bar: 123 .... }
]}
}
}]
}
数据class结构如下:
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 支持可能允许手动解析这些内部数据 classes 的适配器,但我找不到合适的教程或示例。理想情况下,我希望整个 Response 就像定义明确的 JSON.
一样被解析
我是这样使用的retrofit/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)
}
如何实现?任何示例或参考实施都会有所帮助。
欢迎来到多态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
制作自定义适配器
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
}
}
我无法解析 JSON(使用 Moshi)的某些内部部分,这些部分可能变化很大且高度非结构化。整体看起来像:
response: {
items: [{
type: "typeA",
data: {
"1563050214700-001": {
foo: 123 ....
}
}
}, {
type: "typeB",
data: {
"1563050214700-002": {[
// differs a lot from previous one
{bar: 123 .... }
]}
}
}]
}
数据class结构如下:
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 支持可能允许手动解析这些内部数据 classes 的适配器,但我找不到合适的教程或示例。理想情况下,我希望整个 Response 就像定义明确的 JSON.
一样被解析我是这样使用的retrofit/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)
}
如何实现?任何示例或参考实施都会有所帮助。
欢迎来到多态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
制作自定义适配器
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
}
}