My use case is that in data classes wherever I have used Boolean as type, in JSON that can either comes as double quote string ("true") or normal boolean (true)
Earlier I was using Gson & it used to automatically handle all these cases but when trying to migrate to moshi I am facing multiple issues. I even wrote custom adapter for it
class BooleanAdapter : JsonAdapter<Boolean>() {
@FromJson
override fun fromJson(reader: JsonReader): Boolean {
return when (reader.peek()) {
JsonReader.Token.BOOLEAN -> reader.nextBoolean()
JsonReader.Token.STRING -> {
when (val value = reader.nextString()) {
"true", "True", "TRUE", "1" -> true
"false", "False", "FALSE", "0" -> false
else -> throw JsonDataException("Invalid boolean value: $value")
}
}
JsonReader.Token.NUMBER -> {
when (val value = reader.nextInt()) {
0 -> false
1 -> true
else -> throw JsonDataException("Invalid boolean value: $value")
}
}
else -> throw JsonDataException("Expected boolean or string or int value but was ${reader.peek()}")
}
}
@ToJson
override fun toJson(writer: JsonWriter, value: Boolean?) {
writer.value(value)
}
}
Then used this to inject Moshi in retrofit
@Singleton
@Provides
@MoshiBuilder
fun providesDeserializer(): Moshi =
Moshi.Builder()
.add(BooleanAdapter())
.build()
And here is a sample data class
@JsonClass(generateAdapter = true)
data class ItemResponse(
@field:JsonAdapter(BooleanAdapter::class)
@Json(name = "mSet") val IsSet: Boolean,
@Json(name = "name") val name: String,
@field:JsonAdapter(BooleanAdapter::class)
@Json(name = "isPrimary") val isPrimary: Boolean
)
Getting the following error
com.squareup.moshi.JsonDataException: Expected a boolean but was STRING at path
In JSON this parameter is coming as "true"
What am I missing here. It seems I made a bad choice to migrate to Moshi
Remove the JsonAdapter inheritance. It's unnecessary with the ToJson and FromJson annotations and is actually causing the subtle problem with Kotlin and boxed primitive types.
By extending JsonAdapter, you are creating an adapter for the boxed type
Boolean, not the primitive typeboolean, but your ItemResponse declares primitve boolean types, so Moshi looks up the adapter for the primitive type, not the boxed type that you have your adapter for.To get the result you want, simply ensure your adapter is for the primitive boolean type.