Reputation: 21237
I'm using kotlinx.serialization in conjunction with retrofit. The json response that I receive will vary in terms of what attributes it will contain. In most cases, the data model in my app has more fields than I will receive in the response. I cannot control this, so I need to handle it in code.
Kotlinx.serialization throws a MissingFieldException
in such cases. I know that when using Json.parse
you can wrap it in a try-catch block and ignore such errors. But since I am using Retrofit, I don't see a way to use that approach:
WebService.kt
interface WebService {
@GET("person.json")
fun getPerson(): Call<MainActivity.Person>
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
@Serializable
data class Person(val name: String, val species: String, val missing: String)
@UnstableDefault
override fun onCreate(savedInstanceState: Bundle?) {
val mediaType = "application/json".toMediaTypeOrNull()
mediaType?.let {
retrofit = Retrofit.Builder()
.addConverterFactory(Json.nonstrict.asConverterFactory(it))
.baseUrl(baseUrl)
.build()
}
webService = retrofit.create(WebService::class.java)
GlobalScope.launch {
val person = fetchPerson(webService)
}
}
private suspend fun fetchPerson(webService: WebService): Person {
return suspendCancellableCoroutine { cont ->
webService.getPerson()
.enqueue(object : Callback<Person> {
override fun onFailure(call: Call<Person>, t: Throwable) {
Log.e(t.toString(), "Unable to get api response")
cont.cancel(t)
}
override fun onResponse(
call: Call<Person>,
response: Response<Person>
) {
if (response.isSuccessful) {
response.body()?.let { cont.resume(it) }
} else {
cont.cancel(IOException("${response.code()}: ${response.errorBody()}"))
}
}
})
}
}
}
The json response (in this made up example) intentionally omits the 'missing' field:
{"name":"me", "species":"superhuman"}
Since that json does not contain the missing
field from the data class, the app crashes and throws the MissingFieldException
. I'm wondering how to avoid this issue in the Retrofit case.
Thanks for any help.
Upvotes: 7
Views: 7545
Reputation: 4015
For others who has already made the property as nullable and still get the issue, set explicitNulls to false
in your JsonBuilder
@OptIn(ExperimentalSerializationApi::class)
val CustomJson = Json {
ignoreUnknownKeys = true
isLenient = true
explicitNulls = false
}
// usage
CustomJson.decodeFromString<Class>(jsonString)
Upvotes: 0
Reputation: 61
Starting from kotlinx.serialization-1.3.0
, you can create the Json object as Json { explicitNulls = false }
. This will help in serializing response with varying fields without throwing the MissingFieldException
and without the need of passing default values.
Upvotes: 3
Reputation: 15423
Actually it can't create Person
object from json as your Person
class constructor wants 3 value. You have to fulfill this requirement to create object.
One possible solution to resolve this is to use default value in Kotlin like this:
data class Person(
var name: String="",
var species: String="",
var missing: String="")
Another solution is to use multiple constructor with varying no of parameters but since you mentioned it may differ over time, so this solution may not handy. Thanks
Upvotes: 14