I have JSON like this:
{"foos":[{"id":1}, {"id":2}]}
I can turn it into List<Foo> pretty simply with GSON, like this:
Type t = new TypeToken<List<Foo>>(){}.getType();
JsonObject resp = new Gson().fromJson(
new JsonParser().parse(json).getAsJsonObject().get("foos",t);
But let's assume that I also have another JSON, where the name of the array and type changes
{"bars":[{"id":3},{"id":9}]}
Of course I could just swap the "foos" parameter for "bars", but if it's possible, I'd like my software to do it for me.
Is there a way to extract the name of the array child with the GSON library?
I'm not sure if I understood what you want correctly, but aren't you referring to the use of generics? I mean you could write a method that returns you a List of your relevant class? Something along the lines of
Type type = new TypeToken<List<MyClass>>() {}.getType();
List<MyClass> myObjects = getMyObjects(new JsonParser().parse(json).getAsJsonObject().get("foos"), type);
public static List<T> getMyObjects(String jsonString, Type type) {
Gson gson = new Gson();
List<T> myList = gson.fromJson(jsonString, type);
return myList;
}
Looking at your JSON examples, I assume that the name of the list element can change, but not the content of the list. If this is correct, you could parse your JSON response just like this:
Type mapType = new TypeToken<Map<String, List<Foo>>>() {}.getType();
Map<String, List<Foo>> map = gson.fromJson(jsonString, mapType);
And then you can access the name of the list with:
String listName = map.keySet().iterator().next();
If the content of the list could also change, things get a bit more complicated...
Related
Is is mandatory to use TypeToken (as recommended in the Gson doc) as type when converting a list into json like below -
new Gson().toJson(dateRange, new TypeToken<List<String>>() {}.getType());
For me below code is also working -
new Gson().toJson(dateRange, List.class);
Just want to make sure that code doesn't break.
As per docs -
If the object that your are serializing/deserializing is a
ParameterizedType (i.e. contains at least one type parameter and may
be an array) then you must use the toJson(Object, Type) or
fromJson(String, Type) method. Here is an example for serializing and
deserializing a ParameterizedType:
Type listType = new TypeToken<List<String>>() {}.getType();
List<String> target = new LinkedList<String>();
target.add("blah");
Gson gson = new Gson();
String json = gson.toJson(target, listType);
List<String> target2 = gson.fromJson(json, listType);
This is the special case, in other cases you can use class type directly.
For reference - http://google.github.io/gson/apidocs/com/google/gson/Gson.html
Hope this helps
I am new to JSON and GSON, and I am taking a JSON feed from an input stream, and put it into an array list of custom objects. The JSON feed contains a single object, which contains an array of more objects. It looks something like this:
{ "container":[
{"item_1":"item one"},
{"item_2":"item two"},
{"item_3":"item three"}
]}
I am currently using a TypeToken with a Map to obtain the container object along with the list of objects as an array list of custom objects. Like so:
InputStreamReader input = new InputStreamReader(connection.getInputStream());
Type listType = new TypeToken<Map<String, ArrayList<Item>>>(){}.getType();
Gson gson = new GsonBuilder().create();
Map<String, ArrayList<Item>> treeMap = gson.fromJson(input, listType);
ArrayList<Item> objects = treeMap.get("container");
input.close();
I would like to know if there is a way to skip the step of creating a Map<String, ArrayList<Item>>, and go directly from the input stream to an ArrayList<Item> using GSON. Just to consolidate my code, creating a map seems like an unnecessary step.
One option is to define a wrapper type which has a container property, and then deserialize the JSON to that type instead of to a Map.
public static class Wrapper {
public List<Item> container;
}
Wrapper wrapper = gson.fromJson(input, Wrapper.class);
List<Item> objects = wrapper.container;
my json object starts with an object, then contains an array of the object I want { "myObjectArray":[ {....} , {....} , {....} ] }, I have made the model file for the object represented in {....} , how do I get this generic collection code to not assume my root element is an array without making a new nested object file
This is what I currently have,
Type listType = new TypeToken<List<T>>() {
}.getType();
List<T> yourClassList = new Gson().fromJson(jsonArray, listType);
but this assumes that my json object is constructed like this [{....}, {....}, {....}] instead of the way I detailed above
Therefore, parsing returns a JsonSyntaxException
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2
Without creating a pointless model object that contains one variable "myObjectArray" which contains a List of myObject , how would I modify a GSON builder to accomodate?
(I am using android so I can't use a lot of the Oracle JVM reflection methods, including ParameterizedTypeImpl)
using
GsonBuilder builder = new GsonBuilder();
mGson = builder.enableComplexMapKeySerialization().create();
listType = new TypeToken<Map<String, List<T>>>() {}.getType();
parsedGSON = mGson.fromJson(reader, listType);
is the answer
GSON creates a LinkedTreeMap object
There is json in my metod. I want json change to object bean. compiler warns and asks to remove generic.
This example does not work:
Gson gson = new Gson();
List<MyBean> myBean = gson.fromJson(
result.getBody(), List<myBean>.class);
So does run, but I can not get to the bean:
Gson gson = new Gson();
List<MyBean> myBean = gson.fromJson(
result.getBody(), List.class);
MyBean.get(0).getFirstName();
error java.lang.ClassCastException: com.google.gson.internal.StringMap cannot be cast to com.home.bean.MyBean
How do I solve this problem?
Try this:
Type myBeanListType = new TypeToken<ArrayList<MyBean>>() {}.getType();
List<MyBean> mappedList = new Gson().fromJson(result.getBody(), myBeanListType );
Your code would have to be changed to:
List<MyBean> myBean = gson.fromJson(result.getBody(), new TypeToken<List<MyBean>>() {}.getType());
Per the Gson user guide here, (under Serializing and Deserializing Generic Types section):
When you call toJson(obj), Gson calls obj.getClass() to get
information on the fields to serialize. Similarly, you can typically
pass MyClass.class object in the fromJson(json, MyClass.class) method.
This works fine if the object is a non-generic type. However, if the
object is of a generic type, then the Generic type information is lost
because of Java Type Erasure.
You can solve this problem by specifying the correct parameterized
type for your generic type. You can do this by using the TypeToken
class.
Hence, you would have to use TypeToken when dealing with generics.
In my Android project I'm trying to convert a received JSONArray to a List. With the help of this SO answer I got a bit further. I now have the following code:
Gson gson = new Gson();
JSONArray jsonArray = NetworkUtilities.getData("mymodeldata");
Type listType = new TypeToken<List<MyModel>>(){}.getType();
List<MyModel> myModelList = gson.fromJson(jsonArray, listType);
Unfortunately it complaints at the last line that the method fromJson(String, Type) in the type Gson is not applicable for the arguments (JSONArray, Type). I don't really know how to solve this.
Does anybody know how I can solve this?
If you see the answer there, you can notice that the first parameter in the fromJson() method was a String(the json object). Try to use the toString() on the JsonArray like this:-
List<MyModel> myModelList = gson.fromJson(jsonArray.toString(), listType);