0

All the API JSON responses would have the following structure:

{
    "status": <Integer>
    "data": <Object or List of Objects>
    "message": <String>
}

the only property that changes is the 'data', which can be any object or list of object. So is there a way to create a BaseResponse class like

open class BaseResponse<T> (
    @SerializedName("status")
    val status: Int,
    @SerializedName("data")
    abstract val `data`: T,
    @SerializedName("message")
    val message: String
)

and the response classes

data class HelloResponse (
    override val `data`: Hello
) : BaseResponse<Hello> {
    data class Hello (
        @SerializedName("hello")
        val hello: String
    )
}


data class HellosResponse (
    override val `data`: List<Hello>
) : BaseResponse<List<Hello>> {
    data class Hello (
        @SerializedName("hello")
        val hello: String
    )
}

What i really want is to only override the data property, so that i don't have to write status and message property for each Response sub data class i write. I dont want to write status and message in my sub class and pass it to base class, cause i'd still write both the properties, so no difference than creating a data class with status and message.

so cannot be like

data class HelloResponse (
    val status: Int,
    override val `data`: Hello,
    val message: String
) : BasicResponse<Hello>(status, `data`, message) {
    data class Hello (
        @SerializedMessage("hello")
        val hello: String
    )
}

Edit: Own Answer

Well I realized that the HelloResponse is actually a waste since i'm only using it to access the actual Hello class. So what i did was to use the Base class directly in Retrofit2 service. Eg:

fun hello(): Call<BaseResponse<Hello>>

or

fun hellos(): Call<BaseResponse<List<Hello>>>

Well you have to directly specify the type with BaseResponse everywhere you use it. Maybe create typeallias

Or you can create alias

typealias HelloResponse = BaseResponse<Hello>

typealias HellosResponse = BaseResponse<List<Hello>>

To manually deserialize json string with Gson, you need to use TypeToken parameter instead of class type.

val hello = Gson().fromJson<BaseResponse<Hello>>(jsonStr, object: TypeToken<BaseResponse<Hello>>(){}.type)

If you use

val hello = Gson().fromJson<BaseResponse<Hello>>(jsonStr, BaseResponse::class.java)

The data property doesn't convert to Hello instead converts to LinkedHashMap

Note: Retrofit2's GsonConverterFactory uses TypeToken internally, so no problem.

1 Answer 1

1

If you don't want to write status and message properties for data subclasses then you cannot expect subclass to have a constructor with status and message magically.

I strongly suggest you to make BaseResponse abstract and make subclasses like following

abstract class BaseResponse<T> {
    @SerializedName("status")
    abstract val status: Int

    @SerializedName("message")
    abstract val message: String

    @SerializedName("data")
    abstract val `data`: T
}

data class HelloResponse (
    override val status: Int,
    override val message: String,
    override val `data`: Hello,
) : BaseResponse<Hello>() {
    data class Hello (
        @SerializedMessage("hello")
        val hello: String
    )
}

You can achieve it in a way you don't need to write override val properties for subclass declarations by sacrificing data classes. However you lose all bounties provided by data class.

abstract class BaseResponse<T> {
    @SerializedName("status")
    abstract val status: Int

    @SerializedName("message")
    abstract val message: String

    @SerializedName("data")
    abstract val `data`: T
}

class HelloResponse: BaseResponse<Hello>() {
    data class Hello (
        @SerializedMessage("hello")
        val hello: String
    )
}

Just a kind reminder, you don't need to use @SerializedName annotation if class property name and json property name are same.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.