Адаптер Moshi для пропуска плохих объектов в Списке <T> - PullRequest
0 голосов
/ 11 января 2019

Я использую Moshi, и мне нужно решить мою проблему с багендом. Иногда, когда я запрашиваю список объектов, некоторые из них не содержат обязательных полей. Конечно, я могу поймать и обработать JsonDataException, но я хочу пропустить эти объекты. Как я могу сделать это с Моши?

Обновление

У меня есть пара моделей для моей задачи

@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.

Ответы [ 2 ]

0 голосов
/ 15 января 2019

Есть решение в решении, которое ловит и игнорирует только после сбоя. Если адаптер элемента прекратил чтение после ошибки, читатель может, например, быть в середине чтения вложенного объекта, и тогда следующий вызов hasNext будет вызван не в том месте.

Как уже упоминал Джесси, вы можете посмотреть и пропустить все значение.

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()
  }
}
0 голосов
/ 11 января 2019

Кажется, я нашел ответ

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

Спасибо "ребята из других тем" =)

...