Разбор json с неработающим удаленным API
Вот мой модельный класс
data class Article(
val id: Int? = 0,
val is_local: Boolean? = false,
val comments: List<Comment?>? = listOf())
а вот джсон
{
"id": 33,
"is_local": "true",
"comments":
[
{ "url": "aaa" },
{ "url": "bbb" },
{ "url": "ccc" )
]
}
я использую этот пользовательский адаптер для возврата значения по умолчанию в случае ошибки разбора, как в моем случае это поле is_local
class DefaultOnDataMismatchAdapter<T> private constructor(private val delegate:
JsonAdapter<T>, private val defaultValue: T?) : JsonAdapter<T>() {
@Throws(IOException::class)
override fun fromJson(reader: JsonReader): T? =
try {
delegate.fromJsonValue(reader.readJsonValue())
} catch (e: Exception) {
println("Wrongful content - could not parse delegate " +
delegate.toString())
defaultValue
}
@Throws(IOException::class)
override fun toJson(writer: JsonWriter, value: T?) {
delegate.toJson(writer, value)
}
companion object {
@JvmStatic
fun <T> newFactory(type: Class<T>, defaultValue: T?):
JsonAdapter.Factory {
return object : JsonAdapter.Factory {
override fun create(requestedType: Type, annotations:
Set<Annotation>, moshi: Moshi): JsonAdapter<*>? {
if (type != requestedType) {
return null
}
val delegate = moshi.nextAdapter<T>(this, type,
annotations)
return DefaultOnDataMismatchAdapter(delegate,
defaultValue)
}
}
}
}
}
и мой тест не пройден и логическое значение не ложно, я добавил вышеупомянутый адаптер для Моши
@Before
fun createService() {
val moshi = Moshi.Builder()
.add(DefaultOnDataMismatchAdapter
.newFactory(Boolean::class.java,false))
.add(KotlinJsonAdapterFactory())
.build()
val retrofit = Retrofit.Builder()
.baseUrl(mockWebServer.url("/"))
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
service = retrofit.create(ApiStores::class.java)
}
@Test
fun getBooleanParsingError() {
enqueueResponse(case1)
val article = service.getArticle().execute()
assert(article.body()!!).isNotNull()
assert(article.body()!!.is_local).isEqualTo(false) // test fail here
}
но когда я изменяю тип данных поля is_local в классе модели, чтобы он не обнулялся, это работает
1 ответ
Проблема в том, что типы kotlin.Boolean
а также kotlin.Boolean?
соответствуют 2 различным типам Java:
kotlin.Boolean
являетсяboolean
Java примитивный типkotlin.Boolean?
являетсяjava.lang.Boolean
Тип Java
В своем тесте вы создали адаптер для kotlin.Boolean
(т.е. Java boolean
тип), в то время как в вашей модели данных у вас есть kotlin.Boolean?
(т.е. java.lang.Boolean
тип). По этой причине, когда метод create(...)
из Factory
Вам звонят, вы находитесь в ситуации, когда type != requestedType
, так что ваш адаптер не создан и KotlinJsonAdapter
используется вместо На данный момент, так как is_local
Поле Json не является логическим (а является строкой), Моши должен поднять исключение.
Если вы измените модель данных или свой адаптер на использование того же типа, вы окажетесь в ситуации, когда type == requestedType
, так что ваш адаптер создан, исключение выдается, как и раньше, но вы добавили catch
блок, который возвращает значение по умолчанию.