Moshi 适配器跳过列表中的坏对象<T>
Moshi adapter to skip bad objects in the List<T>
我使用 Moshi,我需要解决后端有问题的问题。有时,当我请求对象列表时,其中一些不包含必填字段。当然,我可以捕获并处理JsonDataException
,但我想跳过这些对象。我怎样才能用 Moshi 做到这一点?
更新
我有几个模型可以完成我的任务
@JsonClass(generateAdapter = true)
data class User(
val name: String,
val age: Int?
)
@JsonClass(generateAdapter = true)
data class UserList(val list: List<User>)
和越野车 JSON
{
"list": [
{
"name": "John",
"age": 20
},
{
"age": 18
},
{
"name": "Jane",
"age": 21
}
]
}
如您所见,第二个对象没有强制性 name
字段,我想通过 Moshi 适配器跳过它。
看来我找到了答案
class SkipBadListObjectsAdapterFactory : JsonAdapter.Factory {
override fun create(type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
return if (annotations.isEmpty() && Types.getRawType(type) == List::class.java) {
val elementType = Types.collectionElementType(type, List::class.java)
val elementAdapter = moshi.adapter<Any>(elementType)
SkipBadListObjectsAdapter(elementAdapter)
} else {
null
}
}
private class SkipBadListObjectsAdapter<T : Any>(private val elementAdapter: JsonAdapter<T>) :
JsonAdapter<List<T>>() {
override fun fromJson(reader: JsonReader): List<T>? {
val goodObjectsList = mutableListOf<T>()
reader.beginArray()
while (reader.hasNext()) {
try {
elementAdapter.fromJson(reader)?.let(goodObjectsList::add)
} catch (e: JsonDataException) {
// Skip bad element ;)
}
}
reader.endArray()
return goodObjectsList
}
override fun toJson(writer: JsonWriter, value: List<T>?) {
throw UnsupportedOperationException("SkipBadListObjectsAdapter is only used to deserialize objects")
}
}
}
谢谢"guys from the other topics" =)
解决方案中有一个陷阱,仅在失败后捕获并忽略。例如,如果您的元素适配器在出错后停止读取,reader 可能正在读取嵌套对象,然后下一个 hasNext 调用将在错误的位置调用。
如 Jesse 所述,您可以查看并跳过整个值。
class SkipBadElementsListAdapter(private val elementAdapter: JsonAdapter<Any?>) :
JsonAdapter<List<Any?>>() {
object Factory : JsonAdapter.Factory {
override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
if (annotations.isNotEmpty() || Types.getRawType(type) != List::class.java) {
return null
}
val elementType = Types.collectionElementType(type, List::class.java)
val elementAdapter = moshi.adapter<Any?>(elementType)
return SkipBadElementsListAdapter(elementAdapter)
}
}
override fun fromJson(reader: JsonReader): List<Any?>? {
val result = mutableListOf<Any?>()
reader.beginArray()
while (reader.hasNext()) {
try {
val peeked = reader.peekJson()
result += elementAdapter.fromJson(peeked)
} catch (ignored: JsonDataException) {
}
reader.skipValue()
}
reader.endArray()
return result
}
override fun toJson(writer: JsonWriter, value: List<Any?>?) {
if (value == null) {
throw NullPointerException("value was null! Wrap in .nullSafe() to write nullable values.")
}
writer.beginArray()
for (i in value.indices) {
elementAdapter.toJson(writer, value[i])
}
writer.endArray()
}
}
您可以在这里找到可行的解决方案:
修复愉快:)
我使用 Moshi,我需要解决后端有问题的问题。有时,当我请求对象列表时,其中一些不包含必填字段。当然,我可以捕获并处理JsonDataException
,但我想跳过这些对象。我怎样才能用 Moshi 做到这一点?
更新
我有几个模型可以完成我的任务
@JsonClass(generateAdapter = true)
data class User(
val name: String,
val age: Int?
)
@JsonClass(generateAdapter = true)
data class UserList(val list: List<User>)
和越野车 JSON
{
"list": [
{
"name": "John",
"age": 20
},
{
"age": 18
},
{
"name": "Jane",
"age": 21
}
]
}
如您所见,第二个对象没有强制性 name
字段,我想通过 Moshi 适配器跳过它。
看来我找到了答案
class SkipBadListObjectsAdapterFactory : JsonAdapter.Factory {
override fun create(type: Type, annotations: MutableSet<out Annotation>, moshi: Moshi): JsonAdapter<*>? {
return if (annotations.isEmpty() && Types.getRawType(type) == List::class.java) {
val elementType = Types.collectionElementType(type, List::class.java)
val elementAdapter = moshi.adapter<Any>(elementType)
SkipBadListObjectsAdapter(elementAdapter)
} else {
null
}
}
private class SkipBadListObjectsAdapter<T : Any>(private val elementAdapter: JsonAdapter<T>) :
JsonAdapter<List<T>>() {
override fun fromJson(reader: JsonReader): List<T>? {
val goodObjectsList = mutableListOf<T>()
reader.beginArray()
while (reader.hasNext()) {
try {
elementAdapter.fromJson(reader)?.let(goodObjectsList::add)
} catch (e: JsonDataException) {
// Skip bad element ;)
}
}
reader.endArray()
return goodObjectsList
}
override fun toJson(writer: JsonWriter, value: List<T>?) {
throw UnsupportedOperationException("SkipBadListObjectsAdapter is only used to deserialize objects")
}
}
}
谢谢"guys from the other topics" =)
解决方案中有一个陷阱,仅在失败后捕获并忽略。例如,如果您的元素适配器在出错后停止读取,reader 可能正在读取嵌套对象,然后下一个 hasNext 调用将在错误的位置调用。
如 Jesse 所述,您可以查看并跳过整个值。
class SkipBadElementsListAdapter(private val elementAdapter: JsonAdapter<Any?>) :
JsonAdapter<List<Any?>>() {
object Factory : JsonAdapter.Factory {
override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
if (annotations.isNotEmpty() || Types.getRawType(type) != List::class.java) {
return null
}
val elementType = Types.collectionElementType(type, List::class.java)
val elementAdapter = moshi.adapter<Any?>(elementType)
return SkipBadElementsListAdapter(elementAdapter)
}
}
override fun fromJson(reader: JsonReader): List<Any?>? {
val result = mutableListOf<Any?>()
reader.beginArray()
while (reader.hasNext()) {
try {
val peeked = reader.peekJson()
result += elementAdapter.fromJson(peeked)
} catch (ignored: JsonDataException) {
}
reader.skipValue()
}
reader.endArray()
return result
}
override fun toJson(writer: JsonWriter, value: List<Any?>?) {
if (value == null) {
throw NullPointerException("value was null! Wrap in .nullSafe() to write nullable values.")
}
writer.beginArray()
for (i in value.indices) {
elementAdapter.toJson(writer, value[i])
}
writer.endArray()
}
}
您可以在这里找到可行的解决方案:
修复愉快:)