Reputation: 11
I have a problem with Retrofit, which uses static type of class, not runtime type to serialize it's RequestBody.
Let's say i have two classes :
class A{
String a;
}
class B extends A{
String b;
}
Now i want to make a request:
@Post("/someUrl)
Observable<Void> someRequest(@Body A body);
I want to pass A or B instances to someRequest, and serialize them properly basing on class type.
I tried to use RuntimeTypeAdapterFactory, it worked well but it gave me additional field after serialization (type field). My A, B classes will be only used for serialization.
Upvotes: 1
Views: 845
Reputation: 11
I know, this question is old, but really normal solution is to register custom type adapter when you create your Retrofit
instance. Example here.
Also it works with Kotlin sealed classes:
sealed class AbstractBody(val bodyType: String) {
data class A(
val someDataA: String
) : AbstractBody(bodyType = "A")
data class B(
val someDataB: String
) : AbstractBody(bodyType = "B")
}
And in your retrofit creator:
private fun createRetrofit(baseUrl: String, okHttpClient: OkHttpClient) =
Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(
GsonConverterFactory.create(GsonBuilder().withCustomAdapters().create())
)
.build()
private fun GsonBuilder.withCustomAdapters() = apply {
registerTypeAdapter(
AbstractBody::class.java,
JsonSerializer<AbstractBody> { src, _, context ->
when (src) {
is AbstractBody.A ->
context.serialize(src, AbstractBody.A::class.java)
is AbstractBody.B ->
context.serialize(src, AbstractBody.B::class.java)
}
}
)
}
Upvotes: 1
Reputation: 39863
Consider just overloading the method itself:
@Post("/someUrl)
Observable<Void> someRequest(@Body A body);
@Post("/someUrl)
Observable<Void> someRequest(@Body B body);
Upvotes: 1