Parsing JSON with Gson, Object Sometimes Contains List Sometimes Contains Object

Parsing JSON with GSON, object sometimes contains list sometimes contains object

With Gson, the only way I know how to handle situations like this is with a custom Deserializer. For example:

// outputs:
// [Container: obj=[ChildContainer: children=[[Child: id=1], [Child: id=2]]]]
// [Container: obj=[ChildContainer: children=[[Child: id=1]]]]

public class Foo
{
static String json1 = "{\"obj\":{\"children\":[{\"id\":\"1\"},{\"id\":\"2\"}]}}";
static String json2 = "{\"obj\":{\"children\":{\"id\":\"1\"}}}";

public static void main(String[] args)
{
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
gsonBuilder.registerTypeAdapter(Child[].class, new ChildrenDeserializer());
Gson gson = gsonBuilder.create();
Container container1 = gson.fromJson(json1, Container.class);
System.out.println(container1);

Container container2 = gson.fromJson(json2, Container.class);
System.out.println(container2);
}
}

class Container
{
ChildContainer obj;

@Override
public String toString()
{
return String.format("[Container: obj=%1$s]", obj);
}
}

class ChildContainer
{
Child[] children;

@Override
public String toString()
{
return String.format("[ChildContainer: children=%1$s]", Arrays.toString(children));
}
}

class Child
{
String id;

@Override
public String toString()
{
return String.format("[Child: id=%1$s]", id);
}
}

class ChildrenDeserializer implements JsonDeserializer<Child[]>
{
@Override
public Child[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException
{
if (json instanceof JsonArray)
{
return new Gson().fromJson(json, Child[].class);
}
Child child = context.deserialize(json, Child.class);
return new Child[] { child };
}
}

Parse Json with Gson and problems with list

A quick way of doing it is as follows

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.stream.JsonReader;

public class Clazz {
public static void main(String[] args) throws Exception {

String singularJson = "{ Token: { TokenId : '123' } }";
String multipleJson = "{ Token: [{ TokenId : '123' }, { TokenId : '124' }] }";

JsonElement jsonElementToken = new JsonParser().parse(multipleJson);
JsonElement jsonCollectionOrSingular = jsonElementToken.getAsJsonObject().get("Token");
if (jsonCollectionOrSingular.isJsonArray()) {
System.out.println("It is an collection and not a object");
JsonArray jsonArray = jsonCollectionOrSingular.getAsJsonArray();
System.out.println(jsonArray.get(0).getAsJsonObject().get("TokenId"));

} else {
System.out.println("It is an object and not a collection");
JsonObject jsonObject = jsonCollectionOrSingular.getAsJsonObject();
System.out.println(jsonObject.get("TokenId"));

}

}

Gson: handling an optional List

I don't know what is the structure of a class that you are using to deserialize this JSON, but I'd like to sugest that there is a class like this

public class Rule {

private String id;
private String field;
private String type;
private String input;
private String operator;
private List<String> value;

// constructors, getters and setters
}

As you can see the value property is defined as a list of java.lang.String objects. This approach will help us to handle both cases: when value is an array and when it's a simple string value.

What can we do with the Gson? We can create custom deserializer like this

public class CustomSerializer implements JsonDeserializer<Rule> {
public Rule deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {

JsonObject obj = (JsonObject) jsonElement;
JsonElement value = obj.get("value");
List<String> values = new ArrayList();
if (value.isJsonArray()) {

for (JsonElement jsonElement1 : value.getAsJsonArray()) {
String str = jsonElement1.getAsString();
values.add(str);
}
} else {
values.add(value.getAsString());
}
// deserialize other properties

Rule rule = new Rule();
rule.setValue(values);
// set other properties
return rule;
}
}

After that you need to register deserializer with

Gson gson = new GsonBuilder()
.registerTypeAdapter(Rule.class, new CustomSerializer ())
.create();

and you can deserialize JSON object like

{
"id": "date",
"field": "date",
"type": "date",
"input": "text",
"operator": "equal",
"value": "01.01.2016"
}

that is a part of your whole data structure.

Deserialization of sometimes string and sometimes object with Gson

One solution to your problem is to write a TypeAdapter for your class, however if you have only cases like that in your example, you can achieve the same result letting Gson do the job for you using the most generic class you can for deserialization.

What I mean is shown in the below code.

package stackoverflow.questions.q19478087;

import com.google.gson.Gson;

public class Q19478087 {

public class Test {
public int id;
public Object blob;
@Override
public String toString() {
return "Test [id=" + id + ", blob=" + blob + "]";
}

}

public static void main(String[] str){
String json1 = "{\"id\": 1, \"blob\": \"example text\"}";
String json2 = "{\"id\": 2, \"blob\": {\"to\": 1234, \"from\": 4321, \"name\": \"My_Name\"}}";

Gson g = new Gson();
Test test1 = g.fromJson(json1, Test.class);
System.out.println("Test 1: "+ test1);

Test test2 = g.fromJson(json2, Test.class);
System.out.println("Test 2: "+ test2);
}

}

and this is my execution:

Test 1: Test [id=1, blob=example text]
Test 2: Test [id=2, blob={to=1234.0, from=4321.0, name=My_Name}]

In second case, blob will be deserialized as a LinkedTreeMap, so you can access its elements using ((Map) test2.blob).get("to") for example;

Let me know if it's enough or if you are interested also in the type adapter solution.

How to parse JSON if an element is coming as jsonobject sometime and jsonarray sometime

Found the solution here
Gson handle object or array

@Pasupathi your solution is also correct but I want a way using Gson as my service response is too large and complex.

A value of a json str sometimes is a String, sometimes is a object, how could i use gson to parse it

To simplyfy android development, we can ask for the backend developers to change the Mobile API.The new API could returen the json string that cann't change the value.The value of all keys cann't sometimes be a string, sometimes a object.



Related Topics



Leave a reply



Submit