TypeToken usage mandatory? - java

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

Related

class com.google.gson.internal.LinkedTreeMap cannot be cast to class [duplicate]

I have a domain object Foo, and I want to parse some JSON such as
[
{"prop": "val"},
{"prop": "val2"},
]
I want to get a List<Foo>. Something like this
List<Foo> foos = new Gson().fromJson(json, /*what goes here ?*/);
You need to use a TypeToken to correctly express the type. Class is not sufficient in this case, because of the interaction with the generic type.
Type listType = new TypeToken<List<Foo>>(){}.getType();
List<Foo> projects = (List<Foo>) gson.fromJson(response, listType);

JSON strings to collection Java

I have JSON string
For Example
[{
"id":"abc",
"name":"ffa",
"done":0
},
{
"id":"abc",
"name":"ffa",
"done":0
}]
I want to convert this JSON to collection of Examp class.
I've tried use gson.
public static void main(String[] args)
{
Gson gson = new Gson();
Examp a=new Examp(); //Class Examp have 3 fields (id,name,done)
Examp b=new Examp();
a.done=0;
b.done=0;
a.id="foo";
b.id="foo1";
a.name="faa";
b.name="faa1";
ArrayList<Examp> arr= new ArrayList<Examp>();
arr.add(b);
arr.add(a);
String str = gson.toJson(arr);
System.out.println(str); //format check
ArrayList<Examp> collection = gson.fromJson(str, ArrayList.class);
}
At this moment the type of data in collection isn't Examp, but LinkedTreeMap.
I have one question.
How can I access this data (for example name)?
You need a TypeToken
ArrayList<Examp> collection = gson.fromJson(str, new TypeToken<ArrayList<Examp>>(){}.getType());
The TypeToken is kind of a generic hack to get the generic type argument of a generic type use.
Note that you won't be able to use TypeToke with type variables. (You'll be able to use it, but won't get what you want/expect).
You need to use TypeToken:
Type type = new TypeToken<ArrayList<Examp>>() {}.getType();
List<Examp> collection = gson.fromJson(json, type );
Reference on their wiki page:

Parse nested JSON as generic collection with GSON

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

I can't return List<bean> from the Json? Java.lang.ClassCastException

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.

Get element name with GSON

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...

Categories