Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - Retrofit Gson- How to parse JSON String to object at a JSON key in JSON response?

This my JSON response:

{
      "id": 2,
      "name": "Test",
      "content": "{\"type\": \"status\", \"text\": \"Lorem ipsum dummy text.\", \"id\": 1}"
}

These are model structures:

class TestModel {
    public int id;
    public String name;
    public Content content;
}

class Content {
    public int id;
    public String status;
    public String text;
}

I want to parse content's value directly into my Content model object using Retrofit and GsonConvertor. But currently, I am parsing it as a String value than by using Gson.fromJson() convert to my Content model object. Is there any solution to get my expected result?

When I used to parse it using GsonConverterFactory, Retrofit gives callback in onFailure method with this exception:

java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 4 column 19 path $.data[0].content
like image 896
Mohit Chauhan Avatar asked Nov 09 '22 09:11

Mohit Chauhan


1 Answers

The issue is with the JSON response, it is not in the correct JSON format. The "content" field should be an object, not a string:

{
    "id": 2,
    "name": "Test",
    "content": {
        "type": "status",
        "text": "Lorem ipsum dummy text.",
        "id": 1
    }
}

This will allow either gson.fromJson(response, TestModel.class) or RetroFit with a GsonConverterFactory to parse your response correctly into the corresponding object.


Of course, this only applies if you have the ability to change the JSON response you are receiving. If not, first make sure the person who is in control of the response knows that they are doing it wrong. If nothing changes, then you should be able to work around this by changing the content in TestModel to a String:

class TestModel {
    public int id;
    public String name;
    public String content;
}

class Content {
    public int id;
    public String type;
    public String text;
}

Then parsing each object separately:

TestModel testModel = gson.fromJson(response, TestModel.class);
Content content = gson.fromJson(testModel.content, Content.class);

If the response cannot be changed, another option is to create a TypeAdapter for your Content object:

public class ContentAdapter extends TypeAdapter<Content> {

    @Override
    public void write(JsonWriter out, Content value) throws IOException {
        // TODO: Writer implementation
    }

    @Override
    public Content read(JsonReader in) throws IOException {
        if(in.peek() != JsonToken.NULL) {
            return fromJson(in.nextString());
        } else {
            in.nextNull();
            return null;
        }
    }

}

Then add the TypeAdapter to your GSON implementation:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(Content.class, new ContentAdapter()).create();
like image 70
Bryan Avatar answered Nov 15 '22 06:11

Bryan