Gson从Json反序列化泛型 [英] Gson fromJson deserialize generics

查看:122
本文介绍了Gson从Json反序列化泛型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Android应用程序中工作时,我想要制作一个最终的泛型方法来发送HTTP请求(使用loopj)并反序列化它们(使用Gson),但遇到了一个问题。



正如您在使用 gson.fromJson 时可能知道的那样,您不能这样做:

<$ p $ (responseBody,new TypeToken< T>(){} .getType());< code>

  gson.fromJson(responseBody,new TypeToken< ArrayList< T>(){} .getType())

您将 T 传递给您的实际对象(或第二种情况下的实际对象列表),您将获得 LinkedTreeMap 对象(或 LinkedTreeMap 对象列表)。



如果您想要仍然想反序列化泛型类型对象(-s),请参阅下面的答案。



+奖励:loopj + gson的终极通用解决方案

感谢这些帖子的作者和评论者:

http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in -java /



如何获取通用接口的具体类型



Java类型泛型作为GSON的参数

解决方案

将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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆