5

I trying to deserialize this json to array of objects:

[{
    "name": "item 1",
    "tags": ["tag1"]
},
{
    "name": "item 2",
    "tags": ["tag1","tag2"]
},
{
    "name": "item 3",
    "tags": []
},
{
    "name": "item 4",
    "tags": ""
}]

My java class looks like this:

public class MyObject
{
    @Expose
    private String name;

    @Expose
    private List<String> tags = new ArrayList<String>();
}

The problem is json's tags property which can be just empty string or array. Right now gson gives me error: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING

How should I deserialize this json?

I do not have any control to this json, it comes from 3rd pary api.

devha
  • 3,307
  • 4
  • 28
  • 52

6 Answers6

8

I do not have any control to this json, it comes from 3rd pary api.

If you don't have the control over the data, your best solution is to create a custom deserializer in my opinion:

class MyObjectDeserializer implements JsonDeserializer<MyObject> {
    @Override
    public MyObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject jObj = json.getAsJsonObject();
        JsonElement jElement = jObj.get("tags");
        List<String> tags = Collections.emptyList();
        if(jElement.isJsonArray()) {
            tags = context.deserialize(jElement.getAsJsonArray(), new TypeToken<List<String>>(){}.getType());
        }
        //assuming there is an appropriate constructor
        return new MyObject(jObj.getAsJsonPrimitive("name").getAsString(), tags);
    }
}

What it does it that it checks whether "tags" is a JsonArray or not. If it's the case, it deserializes it as usual, otherwise you don't touch it and just create your object with an empty list.

Once you've written that, you need to register it within the JSON parser:

Gson gson = new GsonBuilder().registerTypeAdapter(MyObject.class, new MyObjectDeserializer()).create();
//here json is a String that contains your input
List<MyObject> myObjects = gson.fromJson(json, new TypeToken<List<MyObject>>(){}.getType());

Running it, I get as output:

MyObject{name='item 1', tags=[tag1]}
MyObject{name='item 2', tags=[tag1, tag2]}
MyObject{name='item 3', tags=[]}
MyObject{name='item 4', tags=[]}
Alexis C.
  • 91,686
  • 21
  • 171
  • 177
1

Before converting the json into object replace the string "tags": "" with "tags": []

Srinivasu
  • 1,215
  • 14
  • 32
1

Use GSON's fromJson() method to de serialize your JSON.

You can better understand this by the example given below:

import java.util.ArrayList;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

public class JsonToJava {

/**
 * @param args
 */
public static void main(String[] args) {
    String json = "[{\"firstName\":\"John\", \"lastName\":\"Doe\", \"id\":[\"10\",\"20\",\"30\"]},"
            + "{\"firstName\":\"Anna\", \"lastName\":\"Smith\", \"id\":[\"40\",\"50\",\"60\"]},"
            + "{\"firstName\":\"Peter\", \"lastName\":\"Jones\", \"id\":[\"70\",\"80\",\"90\"]},"
            + "{\"firstName\":\"Ankur\", \"lastName\":\"Mahajan\", \"id\":[\"100\",\"200\",\"300\"]},"
            + "{\"firstName\":\"Abhishek\", \"lastName\":\"Mahajan\", \"id\":[\"400\",\"500\",\"600\"]}]";

    jsonToJava(json);
}

private static void jsonToJava(String json) {
    Gson gson = new Gson();
    JsonParser parser = new JsonParser();
    JsonArray jArray = parser.parse(json).getAsJsonArray();

    ArrayList<POJO> lcs = new ArrayList<POJO>();

    for (JsonElement obj : jArray) {
        POJO cse = gson.fromJson(obj, POJO.class);
        lcs.add(cse);
    }
    for (POJO pojo : lcs) {
        System.out.println(pojo.getFirstName() + ", " + pojo.getLastName()
                + ", " + pojo.getId());
    }
}

}

POJO class:

public class POJO {

  private String        firstName;
  private String        lastName;
  private String[]  id;
  //Getters and Setters.

I hope this will solve your issue.

Ankur Mahajan
  • 3,396
  • 3
  • 31
  • 42
  • Does this handle cases where id:"" ? – devha Jul 22 '15 at 12:37
  • your id should be of array type, it will consider the empty array. One more point your json should be generic means if you are using tags as array then it should follow the same rule throughout. if you give id : [""], it will work. – Ankur Mahajan Jul 22 '15 at 13:33
-1

You are mixing datatypes. You cant have both an Array and a string. Change

"tags": ""

to

"tags": null

and you are good to go.

slott
  • 3,266
  • 1
  • 35
  • 30
  • 1
    Unfortunately I can not change the json, it comes from 3rd party web api. – devha Jul 22 '15 at 11:51
  • 1
    oh - but can't you contact them and point out that there json is invalid? – slott Jul 22 '15 at 11:52
  • Sure I can (and I will) but it might take time to them to fix the api. – devha Jul 22 '15 at 11:54
  • Can you just add a temp fix where you pre-process the json string before feeding it to gson ? – slott Jul 22 '15 at 11:59
  • 1
    Yep, maybe I just go with solution like Srinivasu Talluri explained. – devha Jul 22 '15 at 12:02
  • Or you could use Object as type and then in your get method use instanceOf and cast String to empty array. This way performance penalty is only runtime for the objects you access. – slott Jul 22 '15 at 12:23
-2

Use Jacskon Object Mapper

See below simple example

[http://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/][1]

S Shukla
  • 77
  • 7
  • 2
    Right now im using Gson to deserialize json in my app. To fix this issue i would like to stick with gson if possible. – devha Jul 22 '15 at 12:00
  • User states he is using gson so switching to jackson might not be an option. – slott Jul 22 '15 at 12:01
  • 1
    I don't understand why when someone asks for questions on GSON other people always feel the need to present a Jackson alternative. – Maxime Claude Jan 26 '17 at 13:12
-6

Jackson type safety is way better than Gson. At times you will stackoverflow in Gson.

S Shukla
  • 77
  • 7