Achy97
Achy97

Reputation: 1024

Calling Secondary Constructor in API response Model in Kotlin Android

My JSON Resoponse looks like-

{
    "body": {
        "count": 4,
        "sender": "margarete20181570"
    },
    "inserted_at": "2020-05-07T05:48:14.465Z",
    "type": 1
},
{
    "body": "savanna19562530 hit the SOS button!",
    "inserted_at": "2020-05-06T09:17:36.658Z",
    "type": 2
}

And I am using the Data Class like below to parse the above JSON, what is wrong here!

data class Notification(val body: String, val inserted_at: String, val type: Int) {

constructor(
    msgBody: MessageNotification,
    inserted_at: String,
    type: Int
) : this(msgBody.sender + "Sent you " + msgBody.count + "Messages", inserted_at, type)

}

But this dosent work it gives parsing error like - Expected String , got object

My Api call looks like-

@GET("notifications")
suspend fun getNotifications(
    @HeaderMap headers: HashMap<String, String>
): Response<List<Notification>>

The main objective is how to remodel the code such that the Notification model class' different constructor will be called on different cases such that it does not give such error expecting string, got object or expecting object got string

How should I improve my code to parse the response?

Any help is appreciated!

Upvotes: 2

Views: 776

Answers (2)

Hussain
Hussain

Reputation: 1345

Since you are deserializing the JSON manually, this can a be solution you can try

data class Body(val count: Int, val sender: String)

data class Notification(val body: Any, val insertedAt: String, val type: Int)

Now, Parsing the JSON response

val jsonResponse = JSONArray(/*JSON response string*/) // I am guessing this is an array

    (0 until jsonResponse.length()).forEach {
        val jsonObj = jsonResponse.getJSONObject(it)
        val jsonBody = jsonObj.get("body")
        if (jsonBody is String) {
            // Body field is a String instance
            val notification = Notification(
                body = jsonBody.toString(),
                insertedAt = jsonObj.getString("inserted_at"),
                type = jsonObj.getInt("type")
            )
            // do something
        } else {
            // Body field is a object
            val jsonBodyObj = jsonObj.getJSONObject("body")
            val body = Body(
                count = jsonBodyObj.getInt("count"),
                sender = jsonBodyObj.getString("sender")
            )
            val notification = Notification(
                body = body,
                insertedAt = jsonObj.getString("inserted_at"),
                type = jsonObj.getInt("type")
            )

            // do something
        }
    }

I hope this helps or atleast you get an idea how you approach to solve your problem. You can also check Gson exclusion strategy.

Upvotes: 1

danmaze
danmaze

Reputation: 369

The body field in your JSON is an object and should map to an object defined in your project. You could have a class header like the following for that purpose:

data class Body(val count: Int, val sender: String)

Your Notification class header would then have a Body field to capture that part of your JSON response like so:

data class Notification(val body: Body, val inserted_at: String, val type: Int)

I generally use Gson for deserialization of Retrofit responses. It works really well and is easy to customize. Let me know if something needs clarification.

Upvotes: 0

Related Questions