2

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!

12
  • 1
    body field in your JSON response is object in first and string in second. That may be the case you are getting error. Commented May 7, 2020 at 8:28
  • yes I know the error, that is my question , that how to remodel my data class to catch both the types, and thats why i have introduced secondary constructor also Commented May 7, 2020 at 8:29
  • Which lib do you use for deserialization? Commented May 7, 2020 at 8:40
  • I am just using Retrofit and deserializing using data classes manually Commented May 7, 2020 at 8:41
  • 1
    Does this answer your question? How to handle different data types with same attribute name with Gson? Commented May 7, 2020 at 10:14

2 Answers 2

1

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.

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

7 Comments

actually it is pretty complex as I am using data binding in recycleview and assigning the object as override fun onBindViewHolder(holder: NotificationAdapter.NotificationViewHolder, position: Int) { holder.notificationListItemBinding.notifyItem = notificationList[position] } thats why it would be better if i could directly call the constructor and retrieve the object
i have added the api call , I cannot use that json destructuring @Hussain
Even if you are using view binding, you can make use of conditional binding or custom setters
as i called the api and accepted response with above said data class, it gives error , so please tell what should I put in here : Response<List<Notification>> in place of Notification class as it is automatically trying to type cast into the given model
You can take body as Any, after you receive the response type cast according to you need
|
0

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.

9 Comments

i think this is the same as the deleted answer
I didn't know there was a deleted answer. Have you tried this?
yes its giving error , expecting string , got object
Where exactly do you get that error? I'm guessing it's because of the second object in your JSON response. In the first object, body is an object whereas in the second, body is a string. If you have control over the network API, I suggest you think some more about the body entity so that you can make your format consistent. It seems your body object could use three fields: count, sender, and message. Of course, I'm only speculating as you should know better.
yes I can change the API JSON type , but i just wante to explore if it is possible
|

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.