gson 是否可以使用retrofit2处理开始_ARRAY和BEGIN_OBJECT以获得相同的响应?

3duebb1j  于 2022-11-06  发布在  其他
关注(0)|答案(2)|浏览(185)

首先,抱歉我的英语不好。我有一个小问题,我的公司的应用程序,我开始学习Kotlin几个月前,所以它的一切对我来说都很新鲜,我做了一些小的挖掘我的大部分问题,但这一个我没有找到任何地方。我们有一个服务器provind数据与Joomla API,问题是,当我使用retrofit2来获得数据与查询,在没有找到数据时返回开始_OBJECT,而在找到数据时返回BEGIN_ARRAY。我发现很多地方告诉我们什么时候是一个,什么时候应该是另一个,但这两个都在同一个响应中,还没有。
这是找不到数据时的响应:

{"err_msg":"Produto n\u00e3o encontrado (CALOTA CORSA)","err_code":404,"response_id":"","api":"","version":"1.0","data":{}}

我将这部分的数据类命名为ProductList,而将数据命名为Product,以供将来参考...
这是找到数据时的响应:

{"err_msg":"","err_code":"","response_id":522,"api":"app.produto","version":"1.0","data":[{"codigo":"0340008","filial":"CPS","referencia":"7898314110118","ncm":"38249941","codigosecundario":"146","nome":"WHITE LUB SUPER AEROSSOL 300ML 146","similar":"0012861","parceiro":"","produtosrelacionados":"0012861;0125121;0125945;0340008;0340035;0340169;0343394;0582033;0582954;0610250;1203682;1227480;1227569;1366196;1366761;1450241;1450861","marca":"ORBI QUIMICA","linha":"DESENGRIPANTE","lancamento":"2011-07-28 00:00:00","quantidadeembalagem":"12","unidademedida":"PC","caracteristicas":"OLEO WHITE LUB SUPER AEROSSOL 300ML - DESENGRIPANTE\/ LUBRIFICANTE\/ PROTETIVO 146","lado":"N\/A","ultima_atualizacao_preco":"2022-08-05 10:32:53","valor":"9.99","ultima_atualizacao_estoque":"2022-09-01 00:03:17","estoque":"200"}]}

响应成功后,最多可收到10种不同的产品。
这是我在ViewModel上的改造调用,我正在使用带有改造功能的GsonConverterFactory。

fun getProductByCode(code: String, token: String) {

    RetrofitInstance.chgApi.listProducts(code, token).enqueue(object : Callback<ProductList> {
        override fun onResponse(call: Call<ProductList>, response: Response<ProductList>) {
            if (response.body()?.errCode != "") {
                Log.e("Response", response.body()?.errMsg!!)
                errMsg.value = response.body()?.errMsg!!
            } else {
                errMsg.value = ""
                products.value = response.body()!!.data
            }
        }

        override fun onFailure(call: Call<ProductList>, t: Throwable) {
            Log.e("Error", t.message.toString())
        }
    })
}

第一个数据类

data class ProductList(
    @SerializedName("err_msg") var errMsg : String,
    @SerializedName("err_code") var errCode : String,
    @SerializedName("response_id") var responseId : String,
    @SerializedName("api") var api : String,
    @SerializedName("version") var version : String,
    @SerializedName("data") var data: ArrayList<Product>
)

第二个数据类

@Entity(tableName = PRODUCT_DATABASE)
data class Product(

    @PrimaryKey
    @SerializedName("codigo"                     ) var codigo                   : String,
    @SerializedName("filial"                     ) var filial                   : String,
    @SerializedName("referencia"                 ) var referencia               : String,
    @SerializedName("ncm"                        ) var ncm                      : String,
    @SerializedName("codigosecundario"           ) var codigosecundario         : String,
    @SerializedName("nome"                       ) var nome                     : String,
    @SerializedName("similar"                    ) var similar                  : String,
    @SerializedName("parceiro"                   ) var parceiro                 : String,
    @SerializedName("produtosrelacionados"       ) var produtosrelacionados     : String,
    @SerializedName("marca"                      ) var marca                    : String,
    @SerializedName("linha"                      ) var linha                    : String,
    @SerializedName("lancamento"                 ) var lancamento               : String,
    @SerializedName("quantidadeembalagem"        ) var quantidadeembalagem      : String,
    @SerializedName("unidademedida"              ) var unidademedida            : String,
    @SerializedName("caracteristicas"            ) var caracteristicas          : String,
    @SerializedName("lado"                       ) var lado                     : String,
    @SerializedName("ultima_atualizacao_preco"   ) var ultimaAtualizacaoPreco   : String,
    @SerializedName("valor"                      ) var valor                    : String,
    @SerializedName("ultima_atualizacao_estoque" ) var ultimaAtualizacaoEstoque : String,
    @SerializedName("estoque"                    ) var estoque                  : String,
    var cesta : Int,
    var comprar : Boolean

)

简单的处理方法是更改我的数据类,将字段“data”的类型更改为ArrayList< Product >或仅更改为Product,但是,据我所知,这两者不能同时使用......有什么建议吗?

4ktjp1zp

4ktjp1zp1#

假设,如您的答案所示,您有两个单独的模型类,一个用于成功响应,一个用于错误响应,以及一个公共超类型(例如接口X1M0N1X),您可以使用自定义的JsonDeserializer1来解决这个问题。它应该基于JsonObject的成员和值来决定数据应该被反序列化为哪种类型。这样,您就可以保留data: List<Product>作为ProductList响应。

object ProductListResponseDeserializer : JsonDeserializer<Response> {
    override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Response {
        val jsonObject = json.asJsonObject

        val errCode = jsonObject.getAsJsonPrimitive("err_code").asString
        val errMsg = jsonObject.getAsJsonPrimitive("err_msg").asString

        val responseType = if (errCode.isEmpty() && errMsg.isEmpty())
            ProductList::class.java
            else ProductListError::class.java

        return context.deserialize(json, responseType)
    }
}

(Note:您也可以使用在此处读取并用于模型类中的@SerializedName的单个常量,而不是在此处和模型类中复制字符串"err_code""err_msg"。)
然后,您必须创建一个GsonBuilder,注册反序列化器,并使用Retrofit的GsonConverterFactory来使用自定义的Gson示例:

val gson = GsonBuilder()
    .registerTypeAdapter(Response::class.java, ProductListResponseDeserializer)
    .create()

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl(...)
    .addConverterFactory(GsonConverterFactory.create(gson))
    .build();

在回调中,检查Response示例的类(它是ProductList还是ProductListError)。
1:一般来说,TypeAdapter应该优先于JsonDeserializer,因为它的性能更高,但由于这里的数据无论如何都需要被解析为JsonObject,因此很可能没有区别。

hjzp0vay

hjzp0vay2#

长话短说,我花了一整天的时间,我在这里找到了一个解决方案:
how to handle two different Retrofit response in Kotlin?
只是把我的Callback、Call和Response改为< Any >,创建一个新的模型,根据响应做一些处理。最后的代码:

fun searchProduct(code: String, token: String) {

    RetrofitInstance.chgApi.listProducts(code.uppercase(), token).enqueue(object : Callback<Any> {

        override fun onResponse(call: Call<Any>, response: Response<Any>) {

            val gson = Gson()

            if (response.body().toString().contains("err_msg=, err_code=")) {

                productList = gson.fromJson(gson.toJson(response.body()), ProductList::class.java)
                products.value = productList.data

            } else {

                productListError = gson.fromJson(gson.toJson(response.body()), ProductListError::class.java)
                errMsg.value = productListError.errMsg

            }
        }

        override fun onFailure(call: Call<Any>, t: Throwable) {
            Log.e("Error", t.message.toString())
        }
    })
}

相关问题