Gson Parse Json With Array With Different Object Types
Solution 1:
The Gson User's Guide explicitly covers this:
You have an object with a field tr
that is an array containing arbitrary types.
The users guide explains that you can't directly deserialize such a structure, and recomends:
Use Gson's parser API (low-level streaming parser or the DOM parser JsonParser) to parse the array elements and then use Gson.fromJson() on each of the array elements. This is the preferred approach.
In your case ... it would really depend on what objects were possible in that array. If they are all going to have that same inner object you'd want to do something like...
List<MyUserPojo> list = new ArrayList<MyUserPojo>();
JsonArray array = parser.parse(json).getAsJsonObject().getAsJsonArray("tr");
for (JsonElement je : array)
{
Set<Map.Entry<String,JsonElement>> set = je.getAsObject().entrySet();
JsonElement je2 = set.iterator().next().getValue();
MyUserPojo mup = new Gson().fromJson(je2, MyUserPojo.class);
list.add(mup);
}
And of course, this would need to be inside a custom deserializer for your actual object that would have the tr
and results
fields.
classMyPojo
{
List<MyUserPojo> userList;
int results;
}
classMyUserPojo
{
String userId;
String address;
}
classMyDeserializerimplementsJsonDeserializer<MyPojo>
{
@Overridepublic MyPojo deserialize(JsonElement je, Type type, JsonDeserializationContext jdc)throws JsonParseException
{
List<MyUserPojo> list = newArrayList<MyUserPojo>();
JsonArrayarray= je.getAsJsonObject().getAsJsonArray("tr");
for (JsonElement je2 : array)
{
Set<Map.Entry<String,JsonElement>> set = je2.getAsObject().entrySet();
JsonElementje3= set.iterator().next().getValue();
MyUserPojomup=newGson().fromJson(je3, MyUserPojo.class);
list.add(mup);
}
MyPojomp=newMyPojo();
mp.tr = list;
mp.results = je.getAsObject().getAsJsonPrimitive("results").getAsInt();
return mp;
}
}
Now you're all set - you can use that deserializer and create your object:
Gson gson = newGsonBuilder()
.registerTypeAdapter(MyPojo.class, newMyDeserializer())
.build();
MyPojo mp = gson.fromJson(json, MyPojo.class);
If the a
, b
etc are important ... well, you'll have to figure that out. But the above should get you well on your way to understanding what's going to be needed to deal with your JSON structure.
For completeness sake, the only "hacky" way around this is if there is a fairly limited number of those types and the inner object also is fairly limited in terms of its fields. You could create a POJO that encompasses all the possibilities:
classMyPojo
{
MySecondPojo a;
MySecondPojo b;
...
MySecondPojo f;
}
classMySecondPojo
{
String userId;
String address;
...
String someOtherField;
}
When Gson deserializes JSON it will set any missing fields in your POJO(s) to null
. You could now have tr
be a List
or array of these in your POJO. Again and to emphasize, this is really quite hacky and the wrong way to do it, but I thought I'd explain what would be required to directly parse that array.
Solution 2:
I pick something from each answer and did it this way:
Response Object
publicclassResponse {
private List<Users> tr;
privateint results;
(...)
}
Generic User
publicclassUser{
publicstaticfinalint TYPE_USER_A =0;
publicstaticfinalint TYPE_USER_B =1;
privateString userId;
privateint type;
(...)
}
A
publicclassaextendsUser{
privateString location;
(...)
}
B
publicclassbextendsUser{
privateString adress;
(...)
}
Parsing Method
privateResponsebuildResponseObject(String response) {
Response tls = newResponse();
List<Users> users = newArrayList<users>();
User u;
try {
JSONObjectobject = newJSONObject(response);
tls.setResults(object.getInt("results"));
JSONArray array = object.getJSONArray("tr");
for (int i = 0; i < array.length(); i++) {
JSONObject trs = array.getJSONObject(i);
if (trs.has("a")) {
String json = trns.getString("a");
A a = newGson().fromJson(json,A.class);
a.setType(User.TYPE_USER_A);
users.add(a);
} elseif (trs.has("b")) {
String json = trs.getString("b");
B b= newGson().fromJson(json,B.class);
B.setType(User.TYPE_USER_B);
users.add(b);
}
}
tls.setUsers(users);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return tls;
}
This is not as elegant as I wanted and mix native JsonObjects with Gson methods but works for me.
Solution 3:
Try this code here:
publicclassAddress{
publicString userId;
publicString address;
// ...
}
publicclassResponse{
private HashMap<String, Address> tr;
privateint results;
// ...
}
Usage:
String json ="{\n\"tr\":\n {\n\"a\": {\n\"userId\": \"112\"\n },\n\"b\": {\n\"userId\": \"123\",\n\"address\":\"street dummy\"\n },\n\"c\": {\n\"userId\": \"154\"\n }\n },\n\"results\":3\n}";
Response users = new Gson().fromJson(json, Response.class);
As you may see I needed to modify the structure:
{
"tr":
{
"a": {
"userId": "112"
},
"b": {
"userId": "123",
"address":"street dummy"
},
"c": {
"userId": "154"
}
},
"results":3
}
But unfortunately I don't get it managed to allow multiple keys. Right now I have no idea how to fix this.
Solution 4:
I think this link might help you: https://sites.google.com/site/gson/gson-user-guide#TOC-Collections-Examples
Basically, create a class for your "object" (kind of user I guess), and then use the deserialization code of Gson, like this:
Type collectionType = new TypeToken<Collection<User>>(){}.getType();
Collection<User> users= gson.fromJson(json, collectionType);
Solution 5:
You can create corresponding java classes for the json objects. The integer, string values can be mapped as is. Json can be parsed like this-
Gsongson=newGsonBuilder().create();
Responser= gson.fromJson(jsonString, Response.class);
Here is an example- http://rowsandcolumns.blogspot.com/2013/02/url-encode-http-get-solr-request-and.html
Post a Comment for "Gson Parse Json With Array With Different Object Types"