Gson从Json反序列化泛型 [英] Gson fromJson deserialize generics
问题描述
在Android应用程序中工作时,我想要制作一个最终的泛型方法来发送HTTP请求(使用loopj)并反序列化它们(使用Gson),但遇到了一个问题。
正如您在使用 gson.fromJson
时可能知道的那样,您不能这样做:
<$ p $ (responseBody,new TypeToken< T>(){} .getType());< code>
或
gson.fromJson(responseBody,new TypeToken< ArrayList< T>(){} .getType())
您将 LinkedTreeMap
对象(或 LinkedTreeMap
对象列表)。
如果您想要仍然想反序列化泛型类型对象(-s),请参阅下面的答案。
+奖励:loopj + gson的终极通用解决方案
感谢这些帖子的作者和评论者:
http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in -java /
将JSON对象反序列化为泛型类型java对象
首先,我们需要得到实际的泛型类型 T
。
我们可以通过传递类本身( Class< T> cl
)或者从类对象具有泛型类型( SomeObject< T> someObjectWithGenericType
)。然后,我们需要创建一个类元素< T>
的特殊对象。这将告诉Gson什么类用于反序列化。
public< T> T getObject(String json,SomeObject< T> someObjectWithGenericType){
Class cl = getTypeClassOfObject(someObjWithGenericType);
T object = gson.fromJson(json,new Element< T>(cl));
返回对象;
$ b $ private class getTypeClassOfObject(Object obj){
return(Class)((ParameterizedType)obj.getClass()。getGenericSuperclass())。getActualTypeArguments()[0] ;
}
private class元素< T>实现ParameterizedType {
private Class< T> CL;
public元素(Class< T> cl){
this.cl = cl;
}
public Type [] getActualTypeArguments(){
return new Type [] {cl};
}
public Type getRawType(){
return cl;
}
public Type getOwnerType(){
return null;
如果你的 SomeObject< T> ;
是一个接口(也许是一个回调函数,你将在后面的loopj例子中看到),你可以使用这个方法来代替 getTypeClassOfObject
:
private Class getTypeClassOfInterfaceObject(Object obj){
return(Class)((ParameterizedType)obj.getClass()。getGenericInterfaces )[0])getActualTypeArguments()[0];
将JSON数组反序列化为泛型类型java对象列表
同样的想法,但我们有一个不同的特殊类来帮助Gson反序列化:
public< T>列表与LT; T> getList(String json,SomeObject< T> someObjectWithGenericType){
Class cl = getTypeClassOfObject(someObjWithGenericType);
列表< T> list = gson.fromJson(json,new ListWithElements< T>(cl));
返回列表;
}
private class ListWithElements< T>实现ParameterizedType {
private Class< T> elementsClass;
public ListWithElements(Class< T> elementsClass){
this.elementsClass = elementsClass;
}
public Type [] getActualTypeArguments(){
return new Type [] {elementsClass};
}
public Type getRawType(){
return List.class;
}
public Type getOwnerType(){
return null;
}
}
奖金
正如你将在这里看到的 someObjectWithGenericType
将会是一个回调类型为 T
。
尽管我使用loopj,但我确定可以使用其他异步http客户端来获得相同的结果。
loopj +带有泛型的Gson: object
public< T> void getObject(String url,HashMap< String,String> paramsMap,final GetObjectCallback< T> callback){
RequestParams params = convertParams(paramsMap);
client.get(url,params,new TextHttpResponseHandler(){
@Override
public void onSuccess(int statusCode,Header [] headers,String responseBody){
try {
Class cl = getTypeClassOfInterfaceObject(callback);
T object = gson.fromJson(responseBody,new Element< T>(cl));
if(object!= null){
callback.onSuccess(object);
} else {
callback.onFailure();
}
} catch(Exception e){
e.printStackTrace();
callback.onFailure();
}
}
@Override
public void onFailure(int statusCode,Header [] headers,String responseBody,Throwable错误){
error.printStackTrace();
callback.onFailure();
}
});
$ b $ private RequestParams convertParams(HashMap< String,String> paramsMap){
RequestParams params = new RequestParams(); ();
if(paramsMap!= null){
for(String key:paramsMap.keySet()){
params.put(key,paramsMap.get(key));
}
}
返回参数;
}
public interface GetObjectCallback< T> {
void onSuccess(T item);
void onFailure();
}
loopj +带有泛型的Gson:list p>
public< T> void getList(String url,HashMap< String,String> paramsMap,final GetListCallback< T> callback){
RequestParams params = convertParams(paramsMap);
client.get(url,params,new TextHttpResponseHandler(){
@Override
public void onSuccess(int statusCode,Header [] headers,String responseBody){
try {
Class cl = getTypeClassOfInterfaceObject(callback);
List list = gson.fromJson(responseBody,new ListWithElements< T>(cl));
if(list!= null){
callback.onSuccess(list);
} else {
callback.onFailure();
}
} catch(Exception e){
e.printStackTrace ();
callback.onFailure();
}
}
@Override
public void onFailure(int statusCode,Header [] headers,String responseBody,Throwable error){
error.printStackTrace();
callback.onFailure();
}
});
}
public interface GetListCallback< T> {
void onSuccess(List< T> list);
void onFailure();
}
用法:object
api.getObject(URL,paramsMap,new GetObjectCallback< NewsItem>(){
@Override
public void onSuccess(NewsItem item ){
//做某事
}
@Override
public void onFailure(){
//做某事
}
});
用法:list
api.getList(URL,paramsMap,new GetListCallback< Comment>(){
@Override
public void onSuccess(List< Comment> list){
//做某事
}
@Override
public void onFailure(){
//做某事
}
});
任何改进都非常受欢迎!
While working on an Android app I've faced a problem when I wanted to make an ultimate generic methods to send HTTP-requests (with loopj) and deserialize them (with Gson).
As you may know while using gson.fromJson
you cannot do like this:
gson.fromJson(responseBody, new TypeToken<T>() {}.getType());
or
gson.fromJson(responseBody, new TypeToken<ArrayList<T>>() {}.getType())
Instead of actual object (or list of actual objects in 2nd case) that you've passed as T
, you will get LinkedTreeMap
object (or list of LinkedTreeMap
objects).
If you want an still want to deserialize generic type object(-s) see the answer below.
+Bonus: ultimate generic solution for loopj+gson
Thanks for authors and commenters of these posts:
http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/
How to get concrete type of a generic interface
Java Type Generic as Argument for GSON
解决方案 Deserializing JSON object to generic type java object
First we need to get the actual class of generic type T
.
We can do it by passing the class itself (Class<T> cl
) or by getting class from the object with generic type (SomeObject<T> someObjectWithGenericType
). I will use second case in examples.
Then we need to create a special object of class Element<T>
that will tell Gson what class to use for deserialization.
public <T> T getObject(String json, SomeObject<T> someObjectWithGenericType) {
Class cl = getTypeClassOfObject(someObjWithGenericType);
T object = gson.fromJson(json, new Element<T>(cl));
return object;
}
private Class getTypeClassOfObject(Object obj) {
return (Class) ((ParameterizedType) obj.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
private class Element<T> implements ParameterizedType {
private Class<T> cl;
public Element(Class<T> cl) {
this.cl = cl;
}
public Type[] getActualTypeArguments() {
return new Type[] {cl};
}
public Type getRawType() {
return cl;
}
public Type getOwnerType() {
return null;
}
}
If your SomeObject<T>
is an interface (perhaps a callback, as you will see in loopj examples later), you can use this method instead of getTypeClassOfObject
:
private Class getTypeClassOfInterfaceObject(Object obj) {
return (Class) ((ParameterizedType) obj.getClass().getGenericInterfaces()[0]).getActualTypeArguments()[0];
}
Deserializing JSON array to list of generic type java objects
Same idea, but we have a different special class to help Gson with deserialization:
public <T> List<T> getList(String json, SomeObject<T> someObjectWithGenericType) {
Class cl = getTypeClassOfObject(someObjWithGenericType);
List<T> list = gson.fromJson(json, new ListWithElements<T>(cl));
return list;
}
private class ListWithElements<T> implements ParameterizedType {
private Class<T> elementsClass;
public ListWithElements(Class<T> elementsClass) {
this.elementsClass = elementsClass;
}
public Type[] getActualTypeArguments() {
return new Type[] {elementsClass};
}
public Type getRawType() {
return List.class;
}
public Type getOwnerType() {
return null;
}
}
BONUS
As you will see here someObjectWithGenericType
is going to be a callback with generic type T
.
Even though I use loopj I'm sure any other async http client can be used to achieve same results.
loopj + Gson with generics: object
public <T> void getObject(String url, HashMap<String, String> paramsMap, final GetObjectCallback<T> callback) {
RequestParams params = convertParams(paramsMap);
client.get(url, params, new TextHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, String responseBody) {
try {
Class cl = getTypeClassOfInterfaceObject(callback);
T object = gson.fromJson(responseBody, new Element<T>(cl));
if (object != null) {
callback.onSuccess(object);
} else {
callback.onFailure();
}
} catch (Exception e) {
e.printStackTrace();
callback.onFailure();
}
}
@Override
public void onFailure(int statusCode, Header[] headers, String responseBody, Throwable error) {
error.printStackTrace();
callback.onFailure();
}
});
}
private RequestParams convertParams(HashMap<String, String> paramsMap) {
RequestParams params = new RequestParams();
if (paramsMap != null) {
for (String key : paramsMap.keySet()) {
params.put(key, paramsMap.get(key));
}
}
return params;
}
public interface GetObjectCallback<T> {
void onSuccess(T item);
void onFailure();
}
loopj + Gson with generics: list
public <T> void getList(String url, HashMap<String, String> paramsMap, final GetListCallback<T> callback) {
RequestParams params = convertParams(paramsMap);
client.get(url, params, new TextHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, String responseBody) {
try {
Class cl = getTypeClassOfInterfaceObject(callback);
List<T> list = gson.fromJson(responseBody, new ListWithElements<T>(cl));
if (list != null) {
callback.onSuccess(list);
} else {
callback.onFailure();
}
} catch (Exception e) {
e.printStackTrace();
callback.onFailure();
}
}
@Override
public void onFailure(int statusCode, Header[] headers, String responseBody, Throwable error) {
error.printStackTrace();
callback.onFailure();
}
});
}
public interface GetListCallback<T> {
void onSuccess(List<T> list);
void onFailure();
}
Usage: object
api.getObject(URL, paramsMap, new GetObjectCallback<NewsItem>() {
@Override
public void onSuccess(NewsItem item) {
// do something
}
@Override
public void onFailure() {
// do something
}
});
Usage: list
api.getList(URL, paramsMap, new GetListCallback<Comment>() {
@Override
public void onSuccess(List<Comment> list) {
// do something
}
@Override
public void onFailure() {
// do something
}
});
Any improvements are very welcome!
这篇关于Gson从Json反序列化泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!