Почему Moshi не использует мой пользовательский адаптер?

#kotlin #moshi

#kotlin #moshi

Вопрос:

У нас есть полиморфное поведение, и для его десериализации мы написали для него пользовательский адаптер Moshi.

 @JsonClass(generateAdapter = true)
open class Field
  
 @JsonClass(generateAdapter = true)
data class Field1 (
    @Json(name = "name")
    val name: String
): Field()
  
 @JsonClass(generateAdapter = true)
data class Field2 (
    @Json(name = "address")
    val address: String
): Field()
  

Выше приведена очень упрощенная версия того, что мы делаем. Мы хотели бы использовать сгенерированный Moshi адаптер для дочерних классов ( Field1 и Field2 ), и этот пользовательский адаптер делегирует FromJSON только на основе доступных полей. Вот пользовательский адаптер для Field :

 class FieldAdapter {
    var moshi = Moshi.Builder().build()
    @ToJson
    fun toJson(field: Field): String {
        return ""
    }

    @FromJson
    fun fromJson(json: String): Field {
        val jsonObject = gson.fromJson(json, JsonObject::class.java)
        var field: Field? = null

        if (jsonObject.has("name")) {
            val field1JsonAdapter: JsonAdapter<Field1> = moshi.adapter(Field1::class.java)
            field = field1JsonAdapter.fromJson(json)
        } else if (jsonObject.has("address")) {
            val field2JsonAdapter: JsonAdapter<Field2> = moshi.adapter(Field2::class.java)
            field = field2JsonAdapter.fromJson(json)
        }

        field?.let {
            return it
        }

        throw JsonDataException("Not a valid field JSON")
    }
}
  

Следующий тест не работает:

 @Test
fun testField1Serialization() {
    val json = MockResponseFileReader("field1.json").content

    val moshi = Moshi.Builder().add(FieldAdapter()).build()
    val adapter = moshi.adapter(Field::class.java)

    val field = adapter.fromJson(json)

    val field1 = field as Field1
    assertEquals("abc", field1.name)
}
  

Приведенный выше тест не вызывает FromJSON нашего пользовательского адаптера, однако, если мы изменим val adapter = moshi.adapter(Field::class.java) val adapter = FieldAdapter() (чтобы жестко закодировать пользовательский адаптер), он работает.

Не могли бы вы указать, что мы делаем не так?

Буду признателен за любую помощь.

TIA

Комментарии:

1. мне кажется, все в порядке, не могли бы вы опубликовать файл field1.json и ошибку, возвращенную тестом?

2. @NicolaGallazzi да, я много чего перепробовал, но это не сработало. Прежде чем сдаться, я попробовал реализовать JsonAdapter , и это просто сработало.

Ответ №1:

Для тех, кто сталкивается с такой же проблемой, просто реализуйте JsonAdapter (методы toJSON и FromJSON) в своем пользовательском адаптере JSON, и он просто будет работать.

К сожалению, у меня до сих пор нет ответа на вопрос, почему адаптер из исходного вопроса не будет работать, поскольку именно так это делается в их официальной документации.

Комментарии:

1. В моем случае это сработало, это сводило меня с ума. Дополнительным примечанием является то, что при реализации этого вам все равно придется сохранять @FromJson @ToJson аннотации и

Ответ №2:

Адаптеры Moshi упорядочены по приоритету, поэтому вы всегда хотите добавить адаптер Kotlin после своих пользовательских адаптеров. В противном KotlinJsonAdapterFactory случае он будет иметь приоритет, и ваши пользовательские адаптеры не будут вызваны.

 Moshi.Builder()
       .add(MyCustomAdapter())
       .add(KotlinJsonAdapterFactory())
       .build()