【发布时间】:2021-12-27 16:09:19
【问题描述】:
我的 Android 应用程序中 API 调用的结果可以是一个带有配置的 JSON,它映射到 SupportConfigurationJson 类,或者只是纯 null。当我得到一个 JSON 时,应用程序可以正常工作,但是当我得到 null 时,我得到了这个异常:
kotlinx.serialization.json.internal.JsonDecodingException: Expected start of the object '{', but had 'EOF' instead
JSON input: null
我应该避免在这个项目中使用GSON。我还找到了一个解决方案,API 接口将返回Response<JSONObject>,之后我的存储库应检查此JSONObject 是否为空,如果不是,则将其映射到SupportConfigurationJson。但是在项目中,我们总是使用自定义类的响应,所以我想知道,有没有其他解决方案可以使用 null 或自定义数据类获得响应?
GettSupportConfiguration 用例类:
class GetSupportConfiguration @Inject constructor(
private val supportConfigurationRepository: SupportConfigurationRepository
) {
suspend operator fun invoke(): Result<SupportConfiguration?> {
return try {
success(supportConfigurationRepository.getSupportConfiguration())
} catch (e: Exception) {
/*
THIS SOLUTION WORKED, BUT I DON'T THINK IT IS THE BEST WAY TO SOLVE THE PROBLEM
if (e.message?.contains("JSON input: null") == true) {
success(null)
} else {
failure(e)
}
*/
//I WAS USING THROW HERE TO SEE WHY THE APP ISN'T WORKING PROPERLY
//throw(e)
failure(e)
}
}
}
SupportConfigurationJson 类:
@Serializable
data class SupportConfigurationJson(
@SerialName("image_url")
val imageUrl: String,
@SerialName("description")
val description: String,
@SerialName("phone_number")
val phoneNumber: String?,
@SerialName("email")
val email: String?
)
SupportConfigurationRepository 类:
@Singleton
class SupportConfigurationRepository @Inject constructor(
private val api: SupportConfigurationApi,
private val jsonMapper: SupportConfigurationJsonMapper
) {
suspend fun getSupportConfiguration(): SupportConfiguration? =
mapJsonToSupportConfiguration(api.getSupportConfiguration().extractOrThrow())
private suspend fun mapJsonToSupportConfiguration(
supportConfiguration: SupportConfigurationJson?
) = withContext(Dispatchers.Default) {
jsonMapper.mapToSupportSettings(supportConfiguration)
}
}
fun <T> Response<T?>.extractOrThrow(): T? {
val body = body()
return if (isSuccessful) body else throw error()
}
fun <T> Response<T>.error(): Throwable {
val statusCode = HttpStatusCode.from(code())
val errorBody = errorBody()?.string()
val cause = RuntimeException(errorBody ?: "Unknown error.")
return when {
statusCode.isClientError -> ClientError(statusCode, errorBody, cause)
statusCode.isServerError -> ServerError(statusCode, errorBody, cause)
else -> ResponseError(statusCode, errorBody, cause)
}
}
SupportConfigurationApi 类:
interface SupportConfigurationApi {
@GET("/mobile_api/v1/support/configuration")
suspend fun getSupportConfiguration(): Response<SupportConfigurationJson?>
}
SupportConfigurationJsonMapper 类:
class SupportConfigurationJsonMapper @Inject constructor() {
fun mapToSupportSettings(json: SupportConfigurationJson?): SupportConfiguration? {
return if (json != null) {
SupportConfiguration(
email = json.email,
phoneNumber = json.phoneNumber,
description = json.description,
imageUrl = Uri.parse(json.imageUrl)
)
} else null
}
}
我这样创建改造:
@Provides
@AuthorizedRetrofit
fun provideAuthorizedRetrofit(
@AuthorizedClient client: OkHttpClient,
@BaseUrl baseUrl: String,
converterFactory: Converter.Factory
): Retrofit {
return Retrofit.Builder()
.client(client)
.baseUrl(baseUrl)
.addConverterFactory(converterFactory)
.build()
}
@Provides
@ExperimentalSerializationApi
fun provideConverterFactory(json: Json): Converter.Factory {
val mediaType = "application/json".toMediaType()
return json.asConverterFactory(mediaType)
}
【问题讨论】:
标签: android kotlin retrofit2 json-deserialization android-json