Moshi 解析具有相同键但不同值的字段
Moshi parse fields with the same key but different values
我们的后端发送一个 json 响应,每次都可以包含相同键的不同值。
第一个变体示例
{
"title": "2",
"profile_image": {
"profile_image_id": "4581542",
"sized": "media/up/2020/48/460e689e286ca46b1006b62269ee21a22b6bdabf2496506e34e5d07c5d42c20f_user_photo_160674563705555.sized.JPG",
"sized_w": "556",
"sized_h": "555",
"thumb": "media/up/2020/48/460e689e286ca46b1006b62269ee21a22b6bdabf2496506e34e5d07c5d42c20f_user_photo_160674563705555.thumb.JPG",
"thumb_w": "90",
"thumb_h": "90"
},
"profile": {
"title": "2",
"first_name": "John",
"last_name": "Doe",
"user_online_status": false
}
}
下面是同一响应的另一种变体。请注意,profile_image
字段现在是数组类型,user_online_status
也可以是字符串或布尔值。此外,当 profile_image 为空时,它始终是一个空数组。在任何其他情况下都是对象。
{
"title": "2",
"profile_image": [],
"profile": {
"title": "2",
"first_name": "John",
"last_name": "Doe",
"user_online_status": "0"
}
}
如何在不创建额外模型的情况下使用 Retrofit 和 Moshi 解析此类响应 类?我可以使用自定义适配器吗?能举个例子吗?
您需要创建将手动反序列化 ProfileImage
属性的自定义适配器。当 Moshi 到达 profile_image
属性 时,将调用适配器。
您需要考虑的两种情况:
- 空情况
[]
这是 API 返回 json 数组时的情况。在这种情况下,您将收到 BEGIN_ARRAY
令牌。
- 所需的情况,您需要一个接一个地反序列化每个
ProfileImage
属性。这是您收到 BEGIN_OBJECT
令牌 的时候
必须保留案例的顺序,以确保始终首先检查空案例。
了解代币 here。
class SkipEmptyProfileAdapter: JsonAdapter<ProfileImage>() {
override fun fromJson(reader: JsonReader): ProfileImage? = when (reader.peek()) {
JsonReader.Token.BEGIN_ARRAY -> {
//this the case when [] is returned. Return null
null
}
JsonReader.Token.BEGIN_OBJECT -> {
// here you parse the `profile_image` property
// here you start iterating properties from the json object until END_OBJECT is
// found. By the time END_OBJECT is reached you should have populated the
// ProfileImage object
}
else -> null
}
override fun toJson(writer: JsonWriter, value: ProfileImage?) {
writer.value(value ?: "[]")
}
}
后端团队毕竟没有被解雇,我成了当天的英雄。
我对 profile_image
字段不一致的解决方案:
- 在我的数据 class
中,class 属性与 Any?
的类型不一致
- 实现了自定义 moshi 适配器
- 使用
Map
解析不一致的 json 字段。
class SkipEmptyProfileAdapter {
@FromJson
fun fromJson(response: UserProfileDataResponse): UserProfileDataResponse {
if (response.profileImage is Map<*, *>) {
val map = response.profileImage as Map<String, String>
response.imageUrlParsed = map["sized"]
}
return response
}
}
将适配器包含到 Moshi 生成器
fun provideMoshi(): Moshi {
return Moshi.Builder()
.add(SkipEmptyProfileAdapter()) //the ordering matters
.add(KotlinJsonAdapterFactory())
.build()
}
我们的后端发送一个 json 响应,每次都可以包含相同键的不同值。
第一个变体示例
{
"title": "2",
"profile_image": {
"profile_image_id": "4581542",
"sized": "media/up/2020/48/460e689e286ca46b1006b62269ee21a22b6bdabf2496506e34e5d07c5d42c20f_user_photo_160674563705555.sized.JPG",
"sized_w": "556",
"sized_h": "555",
"thumb": "media/up/2020/48/460e689e286ca46b1006b62269ee21a22b6bdabf2496506e34e5d07c5d42c20f_user_photo_160674563705555.thumb.JPG",
"thumb_w": "90",
"thumb_h": "90"
},
"profile": {
"title": "2",
"first_name": "John",
"last_name": "Doe",
"user_online_status": false
}
}
下面是同一响应的另一种变体。请注意,profile_image
字段现在是数组类型,user_online_status
也可以是字符串或布尔值。此外,当 profile_image 为空时,它始终是一个空数组。在任何其他情况下都是对象。
{
"title": "2",
"profile_image": [],
"profile": {
"title": "2",
"first_name": "John",
"last_name": "Doe",
"user_online_status": "0"
}
}
如何在不创建额外模型的情况下使用 Retrofit 和 Moshi 解析此类响应 类?我可以使用自定义适配器吗?能举个例子吗?
您需要创建将手动反序列化 ProfileImage
属性的自定义适配器。当 Moshi 到达 profile_image
属性 时,将调用适配器。
您需要考虑的两种情况:
- 空情况
[]
这是 API 返回 json 数组时的情况。在这种情况下,您将收到BEGIN_ARRAY
令牌。 - 所需的情况,您需要一个接一个地反序列化每个
ProfileImage
属性。这是您收到BEGIN_OBJECT
令牌 的时候
必须保留案例的顺序,以确保始终首先检查空案例。
了解代币 here。
class SkipEmptyProfileAdapter: JsonAdapter<ProfileImage>() {
override fun fromJson(reader: JsonReader): ProfileImage? = when (reader.peek()) {
JsonReader.Token.BEGIN_ARRAY -> {
//this the case when [] is returned. Return null
null
}
JsonReader.Token.BEGIN_OBJECT -> {
// here you parse the `profile_image` property
// here you start iterating properties from the json object until END_OBJECT is
// found. By the time END_OBJECT is reached you should have populated the
// ProfileImage object
}
else -> null
}
override fun toJson(writer: JsonWriter, value: ProfileImage?) {
writer.value(value ?: "[]")
}
}
后端团队毕竟没有被解雇,我成了当天的英雄。
我对 profile_image
字段不一致的解决方案:
- 在我的数据 class 中,class 属性与
- 实现了自定义 moshi 适配器
- 使用
Map
解析不一致的 json 字段。
Any?
的类型不一致
class SkipEmptyProfileAdapter {
@FromJson
fun fromJson(response: UserProfileDataResponse): UserProfileDataResponse {
if (response.profileImage is Map<*, *>) {
val map = response.profileImage as Map<String, String>
response.imageUrlParsed = map["sized"]
}
return response
}
}
将适配器包含到 Moshi 生成器
fun provideMoshi(): Moshi {
return Moshi.Builder()
.add(SkipEmptyProfileAdapter()) //the ordering matters
.add(KotlinJsonAdapterFactory())
.build()
}