Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

388
Vistas
Moshi adapter to skip bad objects in the List<T>

I use Moshi and I need to solve my problem with a buggy backend. Sometimes, when I request a list of objects, some of them don't contain mandatory fields. Of course, I can catch and process JsonDataException, but I want to skip these objects. How can I do it with Moshi?

Update

I have a couple of models for my task

@JsonClass(generateAdapter = true)
data class User(
        val name: String,
        val age: Int?
)

@JsonClass(generateAdapter = true)
data class UserList(val list: List<User>)

and buggy JSON

{
  "list": [
    {
      "name": "John",
      "age": 20
    },
    {
      "age": 18
    },
    {
      "name": "Jane",
      "age": 21
    }
  ]
}

as you can see, the second object has no mandatory name field and I want to skip it via Moshi adapter.

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

There's a gotcha in the solution that only catches and ignores after failure. If your element adapter stopped reading after an error, the reader might be in the middle of reading a nested object, for example, and then the next hasNext call will be called in the wrong place.

As Jesse mentioned, you can peek and skip the entire value.

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()
  }
}
over 4 years ago · Santiago Trujillo Denunciar

0

It seems I've found the answer

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")
        }
    }
}

Thank you "guys from the other topics" =)

over 4 years ago · Santiago Trujillo Denunciar

0

You can find a working solution here:

https://github.com/square/moshi/issues/1288

Happy fixing :)

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda