Retrofit - add field dynamically during serialization

血红的双手。 提交于 2019-12-13 20:24:09

问题


I'm currently using Retrofit 2.3 in my Android project and recently the API we are using was updated so that it needs to have "version":number in JSON body in all POST requests. So let's say we need to pass UserCredentials object - previously body of the request was simply serialized using GSON converter and looked like this

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

and now it has to have additional "version" field:

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

I've googled couple of hours how to set custom converter factory to retrofit but all I found was how to exclude certain fields from serialization. I know I could simply add "version" field to all my POJOs but I found this approach 'dirty' as it's going to be used only during sending data to server.

Has anyone did something like this previously?


回答1:


I did it but not exactly the way you want, you can create BaseRequest POJO class in which you can use version number and extend that class to other POJO classes you are using like this :

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

Extend this base POJO class is to other POJO classes to use the version number like this :

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

There are lots of benefits of this approach like if you need one more field in your APIs then you don't need to change all of the apis. You can achieve that just by adding a field in your baserequest.




回答2:


Resolved this issue with custom interceptors for OkHTTP client. So I've created custom interceptor that would analyze outgoing request and alter its body JSON data if it meets certain criteria.

okHttpClientBuilder.addInterceptor(CustomInterceptor(1))

Works like a charm!

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


来源:https://stackoverflow.com/questions/53194710/retrofit-add-field-dynamically-during-serialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!