gson的使用细节

关于json,gson是最常用到的一个库。
平常使用时我通常使用Gson gson = new Gson();的方式创建。
但是最近在使用木哥给的一个volley工具时,出现了解析不出来的情况,很是郁闷。
自己看了半天也没找到原因。所以专门再吧gson的使用方法总结一下。
Gson的api地址
Gson User Guide
google也有github page,哈哈,竟然有35页的开源项目。

new Gson()

我之前都是用的这种方式。。。
Gson有两个重要的方法,一个是toJson,一个是fromJson,也就是序列化和反序列化。
比如解析下面这个gson串:

{
    "name" : "Ravi Tamada", 
    "email" : "ravi8x@gmail.com",
    "phone" : {
        "home" : "08947 000000",
        "mobile" : "9999999999"
    }
    
}
先写一个User
public class User {
private String name;
private String email;
private Phone phone;}
再写一个Phone
public class Phone {
private String home;
private String mobile;}
接下来一切都简单了
Gson gson = new Gson();
User user = gson.fromJson(response.toString(), User.class);
mTextViewVolley.setText(user.getName()+"\n"+user.getEmail()+"\n"+"phone:"+user.getPhone().getHome());

gson常用的方法示例

Gson gson = new Gson();
//序列化
MyObject myobj = new MyObject();  
String jsonstr = gson .toJson(myobj);
//反序列化
MyObject myobj = gson.fromJson(jsonstr, MyObject.class);  
//序列化数组
String[] days = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
String numbersJson = gson.toJson(days);
//序列化集合
List<String> myobjs = new ArrayList<String>();
String jsonstr = gson.toJson(myobjs);
//反序列化集合数组
List<MyObject> myobjs = gson.fromJson(str, new TypeToken<ArrayList<MyObject>>(){}.getType());
// Deserialization
Type collectionType = new TypeToken<Collection<Integer>>(){}.getType();
Collection<Integer> ints2 = gson.fromJson(json, collectionType);

PS:如果需要转换的类包括泛型,那么也需要用到TypeToken,通过这个类可以获取具体的类型

注解

然而Gson并没有那么简单。他还可以使用注解:

Expose

此注解作用在属性上,表明当序列化和反序列化的时候,这个属性将会暴露给Gson对象。这个注解只有当创建Gson对象时使用GsonBuilder方式创建并调用了GsonBuilder.excludeFieldsWithoutExposeAnnotation() 方法的时候才有效,否则无效。下面是一个介绍@Expose注解如何使用的例子:

publicclass User {
 @Expose private String firstName;
 @Expose(serialize = false) private String lastName;
 @Expose (serialize = false, deserialize = false) private String emailAddress;
 private String password;
}

如果你以new Gson()的方式创建Gson对象,toJson()方法和fromJson() 方法在序列化和反序列化的时候将会操作这4个属性。然而,如果你使用 Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()来创建Gson对象,Gson 的 toJson() 和 fromJson() 方法将会排除掉 password 字段,这是因为 password 字段没有被注解 @Expose 所标记。 这个 Gson 对象同样会排除 lastName 和 emailAddress 字段,因为注解@Expose的属性 serialize 被设置成了 false。类似的,Gson 将会在反序列化时排除掉 emailAddress 字段,因为 deserialize被设置成了 false。

PS:
如果不希望有某些属性,也可以使用transient屏蔽,如:
transient int val;

SerializedName

用于修改属性序列化成json之后的名字。
  此注解作用在属性上,表明这个属性在序列化成Json的时候,需要将名字序列化成注解的value属性指定的值。
  这个注解将会覆盖任何的FieldNamingPolicy, 包括默认的命名策略。下面是一个介绍@SerializedName注解如何使用的例子:

publicclass SomeClassWithFields {
    @SerializedName("name") privatefinal String someField;
    private final String someOtherField;
    public SomeClassWithFields(String a, String b) {
      this.someField = a;
      this.someOtherField = b;
    }
}

序列化结果是:{"name":"a","someOtherField":"b"}

Since

使用@Since注解去维护版本,比如你有一个REST的API,并且有多个版本的JSON,如果下一个版本JSON中增加了字段,但又不希望所有的版本都在使用这些字段的话,就可以使用

publicclass Example33 {  
  publicstaticvoid main(String[] args) {  
    Gson gson = new GsonBuilder().setVersion(2.0).create();  
    String json = gson.toJson(new ExampleClass());  
    System.out.println("Output for version 2.0...");  
    System.out.println(json);  
      
    gson= new GsonBuilder().setVersion(1.0).create();  
    json = gson.toJson(new ExampleClass());  
    System.out.println("\nOutput for version 1.0...");  
    System.out.println(json);  
      
    gson= new Gson();  
    json = gson.toJson(new ExampleClass());  
    System.out.println("\nOutput for No version set...");  
    System.out.println(json);  
  }  
}  
   
class ExampleClass{  
  String field=  "field";  
  // this is in version 1.0  
  @Since(1.0) String newField1 = "field 1";  
  // following will be included in the version 1.1  
  @Since(2.0) String newField2 = "field 2";  
}  
输出为: 
Output for version 2.0... 
{"field":"field","newField1":"field 1","newField2":"field 2"} 
Output for version 1.0... 
{"field":"field","newField1":"field 1"} 
Output for No version set... 
{"field":"field","newField1":"field 1","newField2":"field 2"} 

Until

和Since相反,如果下一个版本JSON中删除了某个字段,就可以使用,原理同上。

GsonBulider

使用注释之后,我们创建gson就需要用到GsonBuilder
具体设置参数如下

Gson gson = new GsonBuilder()  
        .excludeFieldsWithoutExposeAnnotation() //不导出实体中没有用@Expose注解的属性  
        .enableComplexMapKeySerialization() //支持Map的key为复杂对象的形式  
        .setDateFormat("yyyy-MM-dd HH:mm:ss:SSS")//时间转化为特定格式    
        .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)//会把字段首字母大写,注:对于实体上使用了@SerializedName注解的不会生效.  
        .setPrettyPrinting() //对json结果格式化.  
        .setVersion(1.0)
      .disableHtmlEscaping()//默认是GSON把HTML 转义的,但也可以设置不转义
        .serializeNulls()//把null值也转换,默认是不转换null值的,可以选择也转换,为空时输出为{a:null},而不是{}
        .create();

泛型

如果需要转换的类包括泛型,那么也需要用到TypeToken,通过这个类可以获取具体的类型

publicclass ApiResult<T> {
    privateint ret;
    private String msg;
    private T data;
    publicint getRet() {
        return ret;
    }
  publicvoid setRet(int ret) {
        this.ret = ret;
    }
  public String getMsg() {
        return msg;
    }
  publicvoid setMsg(String msg) {
        this.msg = msg;
    }
  public T getData() {
        return data;
    }
  publicvoid setData(T data) {
        this.data = data;
    }
}
ApiResult<UserInfo> r = GsonUtils.parse(json, new TypeToken<ApiResult<UserInfo>>() {}.getType());

解析JsonArray

以前不知道Gson可以解析JsonArray.所以使用了如下方法,想想真是无知

public static <T> List<T> readJsonArray(JSONArray array, Class<T> entityType){
        Gson gson =new Gson();
        List<T> list = new ArrayList<>();
        for(int i=0;i<array.length();i++){
            try {
                T t = gson.fromJson(array.getJSONObject(i).toString(),entityType);
                list.add(t);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        return list;
    }

以下是gson user guideu中的内容:
Array Examples

Gson gson = new Gson();
int[] ints = {1, 2, 3, 4, 5};
String[] strings = {"abc", "def", "ghi"};

// Serialization
gson.toJson(ints);     // ==> [1,2,3,4,5]
gson.toJson(strings);  // ==> ["abc", "def", "ghi"]

// Deserialization
int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class); 
// ==> ints2 will be same as ints
We also support multi-dimensional arrays, with arbitrarily complex element types.

Collections Examples

Gson gson = new Gson();
Collection<Integer> ints = Lists.immutableList(1,2,3,4,5);

// Serialization
String json = gson.toJson(ints);  // ==> json is [1,2,3,4,5]

// Deserialization
Type collectionType = new TypeToken<Collection<Integer>>(){}.getType();
Collection<Integer> ints2 = gson.fromJson(json, collectionType);
// ==> ints2 is same as ints

Fairly hideous: note how we define the type of collection. Unfortunately, there is no way to get around this in Java.

Collections Limitations

Can serialize collection of arbitrary objects but can not deserialize from it
Because there is no way for the user to indicate the type of the resulting object
While deserializing, Collection must be of a specific generic type
All of this makes sense, and is rarely a problem when following good Java coding practices.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容