Uso Moshi y necesito resolver mi problema con un backend con errores. A veces, cuando solicito una lista de objetos, algunos de ellos no contienen campos obligatorios. Por supuesto, puedo capturar y procesar JsonDataException , pero quiero omitir estos objetos. ¿Cómo puedo hacerlo con Moshi?
Actualizar
Tengo un par de modelos para mi tarea.
@JsonClass(generateAdapter = true) data class User( val name: String, val age: Int? ) @JsonClass(generateAdapter = true) data class UserList(val list: List<User>)y JSON con errores
{ "list": [ { "name": "John", "age": 20 }, { "age": 18 }, { "name": "Jane", "age": 21 } ] } como puede ver, el segundo objeto no tiene un campo de name obligatorio y quiero omitirlo a través del adaptador Moshi.
Hay un problema en la solución que solo detecta e ignora después de fallar. Si su adaptador de elementos dejó de leer después de un error, el lector podría estar en medio de la lectura de un objeto anidado, por ejemplo, y luego la próxima llamada hasNext se llamará en el lugar equivocado.
Como mencionó Jesse, puede mirar y omitir todo el valor.
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() } }Parece que he encontrado la respuesta.
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") } } }Gracias "chicos de los otros temas" =)
Puede encontrar una solución funcional aquí:
Feliz arreglo :)