gson的使用细节

作者: 黑泥卡 | 来源:发表于2016-01-24 17:13 被阅读5241次

    关于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.

    相关文章

      网友评论

      本文标题:gson的使用细节

      本文链接:https://www.haomeiwen.com/subject/jdirkttx.html