Android 改装-在序列化过程中动态添加字段

Android 改装-在序列化过程中动态添加字段,android,gson,retrofit,Android,Gson,Retrofit,我目前正在我的Android项目中使用改型2.3,最近我们使用的API被更新,因此它需要在所有POST请求的JSON正文中包含“version”:number。所以,假设我们需要传递UserCredentials对象——之前请求的主体只是使用GSON转换器序列化的,如下所示 {“用户名”:“我的用户名”,“密码”:“我的密码”} 现在它必须有额外的“版本”字段: {“用户名”:“我的用户名”,“密码”:“我的密码”,“版本”:1} 我在谷歌上搜索了几个小时如何设置定制转换器工厂进行改造,但我所发

我目前正在我的Android项目中使用改型2.3,最近我们使用的API被更新,因此它需要在所有POST请求的JSON正文中包含
“version”:number
。所以,假设我们需要传递UserCredentials对象——之前请求的主体只是使用GSON转换器序列化的,如下所示

{“用户名”:“我的用户名”,“密码”:“我的密码”}

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

{“用户名”:“我的用户名”,“密码”:“我的密码”,“版本”:1}

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


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

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

class BaseRequest{
@SerializedName("version")
public int version= 0;
 }
class UserRequest extends BaseRequest{
  @SerializedName("username")
  public String userName = "";
  @SerializedName("password")
  public String password = "";
}
将此基本POJO类扩展到其他POJO类以使用如下版本号:

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

这种方法有很多好处,比如如果您的API中还需要一个字段,那么就不需要更改所有API。您只需在baserequest中添加一个字段即可实现这一点。

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

我不想这样做,因为有几个因素:“版本”只在API调用期间使用,我更喜欢组合而不是继承。你可以公开你的改型API方法声明,只是为了澄清一下你是如何发送登录数据的吗?根据你的回答,你正在使用Kotlin或其他东西。也许你可以在你的问题中更新标签。我创建了基于Java的解决方案,以防您也尝试应用该解决方案。