【问题标题】:Retrofit - add field dynamically during serialization改造 - 在序列化期间动态添加字段
【发布时间】:2018-11-07 17:28:07
【问题描述】:

我目前在我的 Android 项目中使用 Retrofit 2.3,最近我们使用的 API 已更新,因此它需要在所有 POST 请求的 JSON 正文中包含 "version":number。因此,假设我们需要传递 UserCredentials 对象 - 之前的请求正文只是使用 GSON 转换器序列化,看起来像这样

{"username":"myUsername", "password":"myPassword"}

现在它必须有额外的“版本”字段:

{"username":"myUsername", "password":"myPassword", "version":1}

我已经用谷歌搜索了几个小时如何设置自定义转换器工厂进行改造,但我发现的只是如何从序列化中排除某些字段。我知道我可以简单地将 "version" 字段添加到我所有的 POJO,但我发现这种方法“脏”,因为它只会在向服务器发送数据时使用。

以前有人做过类似的事情吗?

【问题讨论】:

  • 你能公开你的 Retrofit API 方法声明来澄清一下你是如何发送登录数据的吗?
  • 根据您的回答,您正在使用 Kotlin 或其他东西。也许您将该标签更新到您的问题中。我创建了基于 Java 的 Q&A here,以防您也想尝试应用该解决方案。

标签: android gson retrofit


【解决方案1】:

我做到了,但不完全是您想要的方式,您可以创建 BaseRequest POJO 类,您可以在其中使用版本号并将该类扩展到您正在使用的其他 POJO 类,如下所示:

class BaseRequest{
@SerializedName("version")
public int version= 0;
 }

将此基础 POJO 类扩展为其他 POJO 类以使用这样的版本号:

class UserRequest extends BaseRequest{
  @SerializedName("username")
  public String userName = "";
  @SerializedName("password")
  public String password = "";
}

这种方法有很多好处,例如,如果您的 API 中需要多一个字段,则无需更改所有 API。您只需在基本请求中添加一个字段即可实现此目的。

【讨论】:

  • 由于以下几个因素,我不想这样做:“版本”仅在 API 调用期间使用,我更喜欢组合而不是继承
【解决方案2】:

使用 OkHTTP 客户端的自定义拦截器解决了这个问题。因此,我创建了自定义拦截器,它可以分析传出请求并在满足特定条件时更改其主体 JSON 数据。

okHttpClientBuilder.addInterceptor(CustomInterceptor(1))

像魅力一样工作!

import okhttp3.Interceptor
import okhttp3.RequestBody
import okhttp3.Response
import okio.Buffer
import org.json.JSONException
import org.json.JSONObject
import java.io.IOException

class CustomInterceptor (private val version: Int): Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        var request = chain.request()
        val requestBody = request.body()
        val subtype = requestBody?.contentType()?.subtype()
        if(subtype != null
                && subtype.contains("json")) {
            val bodyWithToken = addVersionParamToJSONBody(requestBody)
            if(null != bodyWithToken){
                val requestBuilder = request.newBuilder()
                request = requestBuilder
                        .post(bodyWithToken)
                        .build()
            }
        }
        return chain.proceed(request)
    }

    private fun addVersionParamToJSONBody(requestBody: RequestBody?) : RequestBody? {
        val customRequest = bodyToString(requestBody)
        return try{
            val jsonObject = JSONObject(customRequest)
            jsonObject.put("version", version)
            RequestBody.create(requestBody?.contentType(), jsonObject.toString())
        } catch (e: JSONException){
            e.printStackTrace()
            null
        }
    }

    private fun bodyToString(requestBody: RequestBody?): String{
        return try {
            val buffer = Buffer()
            requestBody?.writeTo(buffer)
            buffer.readUtf8()
        } catch (e: IOException){
            e.printStackTrace()
            ""
        }
    }
}    

【讨论】:

    猜你喜欢
    • 2014-05-20
    • 2012-10-13
    • 1970-01-01
    • 2013-07-26
    • 1970-01-01
    • 2015-04-18
    • 2017-09-09
    • 2012-06-27
    • 1970-01-01
    相关资源
    最近更新 更多