在Android中处理两种不同的JSON类型

时间:2019-04-03 15:57:21

标签: java android json retrofit

我正在使用的API根据对象是否填充而具有两种不同类型的JSON。如果已填充,则为JSON对象,否则为JSON数组,我将如何在Retrofit中进行处理?

"errors": []

不为空

"errors": {
        "licence": [
            "You have too many points on your licence"
        ],
        "general": [
            "An error occurred during your verification, please contact support"
        ]
    }

我该如何使用Retrofit进行处理,以便在处理响应时不会导致错误?

1 个答案:

答案 0 :(得分:0)

这与改造无关,但与您使用的JSON Deserializer无关。 我猜您正在使用GSON适配器进行翻新。然后,您别无选择,只能为响应编写自定义反序列化器。

让我给你看一个例子(在Kotlin中):

  1. 首先,我们必须为响应创建一个基类。在kotlin中,有一个很棒的构造叫做密封类。对于Java,我建议创建两个代表两种状态(空并有数据)并从基类继承的类。
sealed class ErrorResponse {
    object Empty : ErrorResponse()
    data class ApiError(val licence: List<String>, val general: List<String>) : ErrorResponse()
}

//make sure you call function in the retrofit interface is set to the correct type
@GET("errors")
fun getErrorResponse() : Call<ErrorResponse>
  1. 然后,我们必须创建反序列化器并将其注册到gson实例。因此,我们可以告诉gson应该如何处理n型对象。
class ErrorResponseDeserializer : JsonDeserializer<ErrorResponse> {

    override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): ErrorResponse {
        return when(json) {
            is JsonObject -> {
                context.deserialize<ErrorResponse.ApiError>(json, ErrorResponse.ApiError::class.java)
            }
            else -> ErrorResponse.Empty
        }
    }
}

//create gson instance and register the deserializer
val gson = GsonBuilder()
            .registerTypeAdapter(ErrorResponse::class.java, ErrorResponseDeserializer())
            .create()

//use own gson instance for the gson converter factory
Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create(gson))
            ...

  1. 最后一步是检查错误响应的状态。
//or use rxjava / coroutines etc for the response handling
override fun onResponse(call: Call<ErrorResponse>, response: Response<ErrorResponse>) {
                        val body = response.body()

                        when(body) {
                            is ErrorResponse.Empty -> {
                                //TODO handle empty array state
                            }
                            is ErrorResponse.ApiError -> {
                                //TODO handle api errors or whatever you want
                                val general = body.general //smart cast kotlin <3
                            }
                        }
                    }