Reputation: 533
I wanted to parse Objects from JSON
and It works fine, but I wanted to generalize my function, to get every type I want. I tried to use generic type, but It gave me error.
My code:
//It works, but It's not universal
Type type = new TypeToken<List<WeatherParameter>>(){}.getType();
List<WeatherParameter> contactList = new Gson().fromJson(json, type);
//My function:
public static <T> List<T> getArrayFromJSON(String json) {
Type type = new TypeToken<List<T>>(){}.getType();
return new Gson().fromJson(json, type);
}
Usage:
List<WeatherParameter> contactList = getArrayFromJSON(json);
//Error:
com.google.gson.internal.LinkedTreeMap cannot be cast to com.entity.model.WeatherParameter.
Why generic type T
doesn't work in a TypeToken<List<T>>
?
UPDATE
I've changed my function:
public static <T> List<T> getArrayFromJSON(String json, Class<T> clazz) {
Type type = new TypeToken<List<T>>(){}.getType();
List<T> list = new ArrayList<T>();
List<Object> objectList = GSON.fromJson(json, type);
for(Object o : objectList){
list.add(clazz.cast(o));
}
return list;
}
And it crashes on line list.add(clazz.cast(o));
, error is the same: ClassCastException
.
Full stack trace:
java.lang.ClassCastException: Cannot cast com.google.gson.internal.LinkedTreeMap to com.entity.model.WeatherParameter
at java.lang.Class.cast(Class.java:3361)
at com.server.utils.JsonUtils.getArrayFromJSON(JsonUtils.java:23)
at com.server.task.ShowDataTask.process(ShowDataTask.java:21)
at com.server.task.AbstractTask.run(AbstractTask.java:16)
at com.server.utils.TaskUtils.lambda$doGet$1(TaskUtils.java:17)
at com.server.utils.TaskUtils$$Lambda$22/18975860.handle(Unknown Source)
at spark.RouteImpl$1.handle(RouteImpl.java:61)
at spark.http.matching.Routes.execute(Routes.java:61)
at spark.http.matching.MatcherFilter.doFilter(MatcherFilter.java:128)
at spark.embeddedserver.jetty.JettyHandler.doHandle(JettyHandler.java:50)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:189)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
at org.eclipse.jetty.server.Server.handle(Server.java:534)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:320)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.executeProduceConsume(ExecuteProduceConsume.java:303)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:148)
at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:136)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:671)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:589)
at java.lang.Thread.run(Thread.java:745)
As I said, 23 line in JsonUtils: list.add(clazz.cast(o));
I call it this way:
List<WeatherParameter> weatherParameterList = JsonUtils.getArrayFromJSON(json, WeatherParameter.class);
Upvotes: 1
Views: 1099
Reputation: 522007
The basic reason why your generic method is failing compilation is that after type erasure, the getArrayFromJSON()
method returns a List<Object>
, not a List<WeatherParameter>
. Suppose that the compiler allowed your code to pass. Then it would be possible for you to assign a list of objects to list of weather parameters. But not every object is a weather parameter, so this might fail in a class cast exception.
One way to get around this would be to pass type information for the WeatherParameter
class to your custom method, i.e.
public static <T> List<T> getArrayFromJSON(String json, Class<T> clazz) {
// use class information somehow...
}
You might have a hard time since the class information would probably be needed inside the GSON library.
Have a look at the following question to get thinking about this:
How to have Java method return generic list of any type?
Upvotes: 4