0

I'm not sure if polymorphic is the right term to use so my apologies.

I'm working with the following API:

Request body:

{
    "user_id": "user_id",
    "command": "submit_document",
}

Response:

{
    "result": "success",
    "code": 200,
    "status": "ok",
    "screen": "documents_rejected", // This is unique for different `data`
    "next_screen": "",
    "message": "Successful",
    "data": {
       // `data` is always a json object with known fields and parameters
    }
}

I have data classes ready for different types of data responses like:

data class PhoneData(
        @SerializedName("phone_number")
        val phoneNumber: String? = null,
        @SerializedName("phone_status")
        val phoneStatus: String? = null
)

for "screen": "phone" and the following for another screen:

data class Data(
        val deepLink: String? = null
)

The problem is, at the start, I have to make the following request to retrieve the current screen:

{
    "user_id": "user_id",
    "command": "get_current_screen",
}

which returns a similar response as above:

{
    "result": "success",
    "code": 200,
    "status": "ok",
    "screen": "main_screen", // Different types of screen types are known.
    "next_screen": "",
    "message": "Successful",
    "data": {
       // `data` is always a json object but the object could contain anything depending on the `screen` type.
    }
}

but the data field could contain anything depending on the screen

data class SplashScreenData(
        // How do I make this data class combine all other data classes? One ugly approach is to add all the fields from different `data` classes here and use this one only.
)

I found about the RuntimeTypeAdapterFactory for polymorphic cases but am not sure how to make it work when there's no "type" like field within the data object (screen is unique but it's outside the data object).

It would be very helpful if someone has a solution or could point me in a direction.

  • Do you know what type data is when you make the call to get it? If so, you can make the data's type a template parameter and parse it that way (you have to tell GSON what the template is). If you don't know it but there's a fixed set of possibilities, you can write a custom deserializer that looks at the data and correctly deserializes it, but then data would probably need to be type Any. – Gabe Sechan Nov 20 '21 at 07:06
  • No. I don't know the type when making the call. Yes, there's a fixed set of possibilities. Will try that, Thanks! – Naveen Singh Nov 20 '21 at 07:13
  • You can use `screen` parameter to deserialize or serialize the `data` object into its respective class. – Vaibhav Goyal Nov 20 '21 at 10:09
  • Don't know why you didn't try to search before and save your and others time, but Gson has almost a built-in for this: https://stackoverflow.com/questions/19588020/gson-serialize-a-list-of-polymorphic-objects/22081826#22081826 – terrorrussia-keeps-killing Nov 21 '21 at 08:53

1 Answers1

1
                val frameTextReceived: String = frame.readText()
                val jsonObject = JsonParser.parseString(frameTextReceived).asJsonObject
                val type = when (jsonObject.get("type").asString) {
                    TYPE_JOIN_ROOM -> JoinRoom::class.java
                    TYPE_GAME_MOVE -> GameMove::class.java
                    TYPE_DISCONNECT_REQUEST -> DisconnectRequest::class.java
                    else -> BaseModel::class.java
                }
                val payload = gson.fromJson(frameTextReceived, type)

This is my solution, here I have type parameter by which I can know in which class I have to deserialize the object but in your case you have screen parameter, you can use this.

Vaibhav Goyal
  • 1,692
  • 1
  • 8
  • 23