Gson 在泛型情况下的使用心得

参考链接:
1. https://www.jianshu.com/p/e740196225a4
2. https://www.jianshu.com/p/d62c2be60617

Gson的基本使用

Gson提供了fromJson() 和toJson() 两个直接用于解析和生成的方法,前者实现反序列化,后者实现了序列化。

POJO类的生成与解析
//JSON串1
{
    "code": "0",
    "msg": "操作成功",
    "data": {
        "name": "arsenal",
        "age": 21,
        "sex": "男",
    }
}

要解析上面的Json串,我们需要定义下面两个类:

public class Person {
  private String name;

  private int age;

  private String sex;

  //省略了getter\setter 方法
}

public class Payload {
  private String code;

  private String msg;

  private Person data;

  //省略了getter\setter 方法
}

解析JSON:

Gson gson = new Gson();
String jsonString = "{
    \"code\": \"0\",
    \"msg\": \"操作成功\",
    \"data\": {
        \"name\": \"arsenal\",
        \"age\": 21,
        \"sex\": \"男\",
    }
}";
Payload payload = gson.fromJson(jsonString, Payload.class);

生成JSON:

Payload payload = new Payload();
payload.setCode("0");
...
String jsonStr = gson.toJson(payload);
Gson中使用泛型

对于在Java中使用泛型,存在泛型擦除的问题,即对于Java来说List<String>List<User> 这俩个的字节码文件只一个那就是List.class

对于下面的JSON:

//JSON串2
{
    "code": "0",
    "msg": "操作成功",
    "data": [
        {
            "name": "arsenal",
            "age": 21,
            "sex": "男",
        },
        {
            "name": "stern",
            "age": 22,
            "sex": "男",
        }
    ]

}

解析JSON串2,我们需要将Payload类修改为:

public class Payload<T> {
  private String code;

  private String msg;

  private T data;

  //省略了getter\setter 方法
}

则JSON串2对应的实体类为 Payload<List<Person>>,此时就不能使用 Payload.class 来进行JSON串的解析了。为了解决的上面的问题,Gson为我们提供了TypeToken来实现对泛型的支持:

Gson gson = new Gson();
String jsonArray = "{
    \"code\": \"0\",
    \"msg\": \"操作成功\",
    \"data\": [
        {
            \"name\": \"arsenal\",
            \"age\": 21,
            \"sex\": \"男\",
        },
        {
            \"name\": \"stern\",
            \"age\": 22,
            \"sex\": \"男\",
        }
    ]

}";
List<String> stringList = gson.fromJson(jsonArray, new TypeToken<Payload<List<Person>>>() {}.getType());

//ps:TypeToken的构造方法是protected修饰的,所以上面才会写成new TypeToken<Payload<List<Person>>>() {}.getType() 而不是  new TypeToken<Payload<List<Person>>>().getType()
//百度“匿名内部类”
Gson 泛型使用的进一步封装

每次都需要根据具体类型来写new TypeToken<Payload<List<Person>>>() {}.getType(),比较麻烦。下面我们将对Payload类进行进一步封装。

Type是Java中所有类型的父接口,在1.8以前是一个空接口,自1.8起多了个getTypeName()方法,下面有ParameterizedType、 GenericArrayType、 WildcardType、 TypeVariable 几个接口,以及Class类。

ParameterizedType 简单说来就是形如“ 类型<> ”的类型,如:Map< String,User >。下面就以 Map < String, User > 为例讲一下里面各个方法的作用。

public interface ParameterizedType extends Type {
     // 返回Map<String,User>里的String和User,所以这里返回[String.class,User.clas]
    Type[] getActualTypeArguments(); 
    // Map<String,User>里的Map,所以返回值是Map.class
    Type getRawType();
    // 用于这个泛型上中包含了内部类的情况,一般返回null
    Type getOwnerType(); 
}

有了上面的知识,我们可以把Payload修改为:

public class Payload<T> {
  private String code;

  private String msg;

  private T data;

  //省略了getter\setter 方法

  public static Payload fromJson(String json, Class clazz) {
    Gson gson = new Gson();
    Type listType = new ParameterizedType() {
      public Type getRawType() {
        return List.class;
      }
      public Type[] getActualTypeArguments() {
        return new Type[]{clazz};
      }
      public Type getOwnerType() {
        return null;
      }
    }
    Type objectType = new ParameterizedType() {
      public Type getRawType() {
        return Payload.class;
      }
      public Type[] getActualTypeArguments() {
        return new Type[]{listType};
      }
      public Type getOwnerType() {
        return null;
      }
    }
    return gson.fromJson(json, objectType);
  }
}

这样,我们解析JSON串2,只需要:

Payload<List<Person>> result = Payload.fromJson(jsonStr2, Person);
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值