#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()