Обработка исключения MissingFieldException в Kotlin Serialization с помощью дооснащения

Я использую kotlinx.serialization в сочетании с модифицированной. Ответ json, который я получаю, будет зависеть от атрибутов, которые он будет содержать. В большинстве случаев модель данных в моем приложении содержит больше полей, чем я получу в ответе. Я не могу это контролировать, поэтому мне нужно обработать это в коде.

Kotlinx.serialization бросает MissingFieldExceptionв таких случаях. Я знаю, что при использованииJson.parseвы можете заключить его в блок try-catch и игнорировать такие ошибки. Но поскольку я использую Retrofit, я не вижу способа использовать этот подход:

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()}"))
                        }
                    }
                })
        }
    }
}

Ответ json (в этом надуманном примере) намеренно опускает поле 'missing':

{"name":"me", "species":"superhuman"}

Поскольку этот json не содержит missing поля из класса данных, приложение вылетает и выдает MissingFieldException. Мне интересно, как избежать этой проблемы в случае модернизации.

Спасибо за любую помощь.

3 ответа

Решение

На самом деле это не может создать Person объект из json как ваш Personконструктор класса хочет 3 значения. Вы должны выполнить это требование для создания объекта.

Одно из возможных решений для решения этой проблемы - использовать значение по умолчанию в Kotlin следующим образом:

data class Person(
    var name: String="", 
    var species: String="", 
    var missing: String="") 

Другое решение - использовать несколько конструкторов с разными параметрами, но, как вы упомянули, со временем они могут отличаться, поэтому это решение может оказаться не очень удобным. Спасибо

Начиная с kotlinx.serialization-1.3.0, вы можете создать объект Json как Json { explicitNulls = false }. Это поможет сериализовать ответ с различными полями, не выбрасывая MissingFieldException и без необходимости передавать значения по умолчанию.

Ссылка

Для тех, кто уже сделал свойство обнуляемым и все еще сталкивается с проблемой, установитеexplicitNulls to falseв вашем JsonBuilder

      @OptIn(ExperimentalSerializationApi::class)
val CustomJson = Json {
    ignoreUnknownKeys = true
    isLenient = true
    explicitNulls = false
}

// usage
CustomJson.decodeFromString<Class>(jsonString)

Другие вопросы по тегам