Android 库 Gson

【Android 库 Gson】

引用:

Gson 解析教程
★★★ Gson的入门使用
Gson全解析(上)-Gson基础 ==RTRT==待读
你真的会用Gson吗?Gson使用指南(一)==RTRT==待读

前言

Gson (又称Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为序列化Java对象为JSON字符串,或反序列化JSON字符串成Java对象。而JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成,广泛应用于各种数据的交互中,尤其是服务器与客户端的交互。

基本概念

  • Serialization:序列化,使Java对象到Json字符串的过程。
  • Deserialization:反序列化,字符串转换成Java对象。
  • JSON数据中的JsonElement有下面这四种类型:
    JsonPrimitive —— 例如一个字符串或整型
    JsonObject—— 一个以 JsonElement 名字(类型为 String)作为索引的集合。也就是说可以把 JsonObject 看作值为 JsonElement 的键值对集合。
    JsonArray—— JsonElement 的集合。注意数组的元素可以是四种类型中的任意一种,或者混合类型都支持。
    JsonNull—— 值为null

使用

引入

app的build.gradle中引入:

dependencies {
    implementation 'com.google.code.gson:gson:2.8.5'
}

Gson的两个基础方法

public String toJson(Object src)
public <T> T fromJson(String json, Class<T> classOfT)

Gson的创建

方式一:

直接new Gson对象:

// 使用new方法
Gson gson = new Gson();

// toJson 将bean对象转换为json字符串
String jsonStr = gson.toJson(user, User.class);

// fromJson 将json字符串转为bean对象
Student user= gson.fromJson(jsonStr, User.class);

// **序列化List**
String jsonStr2 = gson.toJson(list);

// **反序列化成List时需要使用到TypeToken getType()**
List<User> retList = gson.fromJson(jsonStr2,new TypeToken<List<User>>(){}.getType());

方式二:

使用GsonBuilder

使用new Gson(),此时会创建一个带有默认配置选项的Gson实例,如果不想使用默认配置,那么就可以使用GsonBuilder。

//serializeNulls()是GsonBuilder提供的一种配置,当字段值为空或null时,依然对该字段进行转换
Gson gson = new GsonBuilder().serializeNulls().create(); 

使用GsonBuilder创建Gson实例的步骤:

  • 首先创建GsonBuilder,然后调用GsonBuilder提供的各种配置方法进行配置,
  • 最后调用GsonBuilder的create方法,将基于当前的配置创建一个Gson实例。

GsonBuilder的一些配置

 Gson gson = new GsonBuilder()
         .excludeFieldsWithoutExposeAnnotation() //不对没有用@Expose注解的属性进行操作
         .enableComplexMapKeySerialization() //当Map的key为复杂对象时,需要开启该方法
         .serializeNulls() //当字段值为空或null时,依然对该字段进行转换
         .setDateFormat("yyyy-MM-dd HH:mm:ss:SSS") //时间转化为特定格式
         .setPrettyPrinting() //对结果进行格式化,增加换行
         .disableHtmlEscaping() //防止特殊字符出现乱码
         .registerTypeAdapter(User.class,new UserAdapter()) //为某特定对象设置固定的序列或反序列方式,自定义Adapter需实现JsonSerializer或者JsonDeserializer接口
         .create();

例如:Gosn对复杂Map的处理时需要用到其中的 enableComplexMapKeySerialization() 配置:

Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create(); //开启复杂处理Map方法
Map<List<User>, String> map = new HashMap<List<User>, String>();
// TODO 向map中添加数据

String jsonStr = gson.toJson(map);  //toJson

Map<List<User>, String> resultMap = gson.fromJson(jsonStr, new TypeToken<Map<List<User>, String>>() {}.getType()); //fromJson

注意:如果Map的key为String,则可以不使用GsonBuilder的enableComplexMapKeySerialization()方法,或者直接new Gson();

Gson的基本用法:

Json字符串转JavaBean

String studentJsonStr="{\"name\":\"xuanyouwu\",\"age\":26}";
Student student = gson.fromJson(studentJsonStr, Student.class);

运行结果:

------->json convert JavaBean:Student{name='xuanyouwu', age=26}

Json字符串转List

反序列化成List时需要使用到TypeToken getType()

String listJsonStr="[\"1\",\"a\",\"3\",\"rt\",\"5\"]";

Type type = new TypeToken<ArrayList<String>>() {}.getType();
ArrayList<String> sList=gson.fromJson(listJsonStr, type);

运行结果:

------->json convert List:[1, a, 3, rt, 5]

JavaBean转换Json字符串

gson提供 public String toJson(Object src) 方法可以将对象转换成jsonStr

public class GsonTest1 {
    public static void main(String[] args) throws Exception {
        Student student = new Student();
        student.setName("xuanyouwu");
        student.setAge(26);
        
        Gson gson = new Gson();
        String jsonStr = gson.toJson(student);
        
        System.out.println("---->javabean convert jsonStr:" + jsonStr);
    }
    public static class Student {
        private String name;
        private int age;
        //省略setter getter equals
    }
}

运行结果:

---->javabean convert jsonStr:{"name":"xuanyouwu","age":26}

List Map转Json字符串

Gson gson = new Gson();

List<String> list = Arrays.asList("1", "a", "3", "rt", "5");
String toJson = gson.toJson(list);        

Map<String, Object> content = new HashMap<String, Object>();
content.put("name", "xuanyouwu");
content.put("age", "26");
String toJson1 = gson.toJson(content);

运行结果:

---->list convert jsonStr:["1","a","3","rt","5"]
---->map convert jsonStr:{"name":"xuanyouwu","age":"26"}

Gson封装的类型体系

Gson里面有一个非常有意思的抽象基类JsonElement,他的继承体系:


JsonObject

JsonObject等同于org的JSONObject,JsonArray也类似,

addPropert(key,value)

通过addPropert(key,value)可以向jsonObject中添加字段 跟hashMap类似

JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("name", "xuanyouwu");
jsonObject.addProperty("age", 26);
System.out.println("------>create jsonObject:" + jsonObject);

运行结果:

------>create jsonObject:{"name":"xuanyouwu","age":26}

JsonArray

JsonArray jsonElements = new JsonArray();
jsonElements.add("a");
jsonElements.add("b");
jsonElements.add("c");
jsonElements.add("d");
System.out.println("------>create jsonArray:" + jsonElements);

运行结果:

------>create jsonArray:["a","b","c","d"]

JsonObject 嵌套数组或者说嵌套JsonArray

通过JsonObject的add(key,JsonElement)可以为jsonObject 添加一个数组的字段

JsonObject jsonObject2 = new JsonObject();
jsonObject2.addProperty("name", "xuanyouwu");
jsonObject2.addProperty("age", 26);

JsonArray jsonElements2 = new JsonArray();
jsonElements2.add("骑车");
jsonElements2.add("打游戏");
jsonElements2.add("看电视");
jsonObject2.add("hobby", jsonElements2);

System.out.println("------>create jsonObject inner JsonArray:" + jsonObject2);

运行结果:

------>create jsonObject inner JsonArray:{"name":"xuanyouwu","age":26,"hobby":["骑车","打游戏","看电视"]}

JsonNull

JsonNull 其实就是null 字段

JsonNull jsonNull=new JsonNull();//构造方法过时,推荐INSTANCE
JsonNull jsonNull=JsonNull.INSTANCE;
System.out.println("-----"+jsonNull);

运行结果:

-----null

JsonPrimitive

JsonPrimitive非常有意思,我们知道如果json转换成字符串可能包含引号的转义,但是通过JsonPrimative我们可以获得为转义的字符串,看实例:

String studentJsonStr = "{\"name\":\"xuanyouwu\",\"age\":26}";
System.out.println("------>studentJsonStr:" + studentJsonStr);


JsonPrimitive jsonPrimitive = new JsonPrimitive(studentJsonStr);
System.out.println("------>jsonPrimitive:" + jsonPrimitive);
System.out.println("------>jsonPrimitive:" + jsonPrimitive.toString());
System.out.println("------>jsonPrimitive:" + jsonPrimitive.getAsString());

JsonPrimitive jsonPrimitive2 = new JsonPrimitive("this is String");
System.out.println("------>jsonPrimitive2:" + jsonPrimitive2);
System.out.println("------>jsonPrimitive2:" + jsonPrimitive2.toString());
System.out.println("------>jsonPrimitive2:" + jsonPrimitive2.getAsString());

运行结果:

------>studentJsonStr:{"name":"xuanyouwu","age":26}
------>jsonPrimitive:"{\"name\":\"xuanyouwu\",\"age\":26}"
------>jsonPrimitive:"{\"name\":\"xuanyouwu\",\"age\":26}"
------>jsonPrimitive:{"name":"xuanyouwu","age":26}
------>jsonPrimitive2:"this is String"
------>jsonPrimitive2:"this is String"
------>jsonPrimitive2:this is String

Gson注解

在Gson中有五类注解


@SerializedName 重命名

作用1:转换关键字key

场景1:json转换成JavaBean时,json字段的key 默认必须和我们声明类的字段名称一样,当服务器端返回了关键字怎么办,比如key 为new switch这样,我们在声明类的时候不能写这样的字段。这时候重命名注解都排上用场了。
场景2:服务器端返回的json 的key 简直太丑,或者太长,你想简化,my_parent_name,可以简化成mpn 比较优雅简介

实例:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public static class User {
        public String name;
        public int age;

        @SerializedName("new")
        public int isnew;

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", isnew=" + isnew +
                    '}';
        }
    }

    public static void main(String[] args) throws Exception {
        String jsonFromServer = "{\n" +
                "    \"age\": 26,\n" +
                "    \"name\": \"zhangsan\",\n" +
                "    \"new\": 1\n" +
                "}";


        Gson gson = new Gson();
        User user = gson.fromJson(jsonFromServer, User.class);
        System.out.println("------>user:" + user);

    }
}

运行结果:

------>user:User{name='zhangsan', age=26, isnew=1}
public class GsonTest {

    public static class User2 {
        public String name;
        public int age;

        @SerializedName("my_parent_name")
        public String pn;

        @Override
        public String toString() {
            return "User2{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", pn='" + pn + '\'' +
                    '}';
        }
    }


    public static void main(String[] args) throws Exception {
        String jsonFromServer2 = "{\n" +
                "    \"age\": 26,\n" +
                "    \"my_parent_name\": \"zhangsanf\",\n" +
                "    \"name\": \"zhangsan\"\n" +
                "}";


        Gson gson2 = new Gson();
        User2 user2 = gson2.fromJson(jsonFromServer2, User2.class);
        System.out.println("------>user2:" + user2);
    }
}

运行结果:

------>user2:User2{name='zhangsan', age=26, pn='zhangsanf'}

作用2:结合alternate 提供多种备用字段key来解析

@SerializedName(value ="desc",alternate = {"other","note"}) 如果json中有other就会解析成desc 如果有note也会解析成desc。
注意1:value中的值不能出现在alternate中;
注意2:alternate的备选字段,会后面的替换前面的。

实例:

public class GsonTest {
    public static class User {
        public String name;
        public int age;
        @SerializedName(value = "desc", alternate = {"other", "note"})
        public String desc;

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", desc='" + desc + '\'' +
                    '}';
        }
    }

    public static void main(String[] args) throws Exception {
        String jsonFromServer = "{\n" +
                "    \"age\": 26,\n" +
                "    \"other\": \"成都人\",\n" +
                "    \"name\": \"zhangsan\"\n" +
                "}";
        Gson gson = new Gson();
        User user = gson.fromJson(jsonFromServer, User.class);
        System.out.println("------>user:" + user);


        String jsonFromServer2 = "{\n" +
                "    \"age\": 26,\n" +
                "    \"note\": \"成都人\",\n" +
                "    \"name\": \"zhangsan\"\n" +
                "}";
        User user2 = gson.fromJson(jsonFromServer2, User.class);
        System.out.println("------>user:" + user2);

        //包括desc与note,note在后面
        String jsonFromServer3 = "{\n" +
                "    \"age\": 26,\n" +
                "    \"desc\": \"desc成都人\",\n" +
                "    \"name\": \"zhangsan\",\n" +
                "    \"note\": \"note成都人\"\n" +
                "}";
        User user3 = gson.fromJson(jsonFromServer3, User.class);
        System.out.println("------>user:" + user3);

        //包括desc与note,desc在后面
        String jsonFromServer4 = "{\n" +
                "    \"age\": 26,\n" +
                "    \"note\": \"note成都人\",\n" +
                "    \"name\": \"zhangsan\",\n" +
                "    \"desc\": \"desc成都人\"\n" +
                "}";
        User user4 = gson.fromJson(jsonFromServer4, User.class);
        System.out.println("------>user:" + user4);
    }
}

运行结果:

------>user:User{name='zhangsan', age=26, desc='成都人'}
------>user:User{name='zhangsan', age=26, desc='成都人'}
------>user:User{name='zhangsan', age=26, desc='note成都人'}
------>user:User{name='zhangsan', age=26, desc='desc成都人'}

@Expose 过滤

可以排除不需要序列化的字段,默认既可以序列化又可以反序列化

/* Expose 源码 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Expose {  
  public boolean serialize() default true; 
  public boolean deserialize() default true;
}

需要配合GsonBuilder使用

Gson gson = new GsonBuilder()
                .excludeFieldsWithoutExposeAnnotation()
                .create();

如上设置后,不添加@Expose注解的字段将不会解析:
分为以下几种情况:
1:不添加@Expose注解等同于@Expose(deserialize = false,serialize = false) 做任何解析
2:@Expose(deserialize = true,serialize = false)可解析用用,也就是反序列化,不可以序列化
3:@Expose(deserialize = false,serialize = true) 序列化可以,反序列化不行
4:@Expose(deserialize = true,serialize = true) 既可以序列化,也可以反序列化

情况1

不添加@Expose注解,等同于@Expose(deserialize = false,serialize = false)

public class GsonTest5 {
    public static class User {
        public String name;
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }

    public static void main(String[] args) throws Exception {
        String jsonFromServer = "{\"name\": \"zhangsan\"}";
        
        Gson gson = new GsonBuilder()
                .excludeFieldsWithoutExposeAnnotation()
                .create();
        User user = gson.fromJson(jsonFromServer, User.class);
        System.out.println("------>反序列化:" + user);

        User user1 = new User();
        user1.name = "zhangsan2";
        String userStr = gson.toJson(user1);
        System.out.println("------>序列化:" + userStr);
    }
}

运行结果:

------>反序列化:User{name='null'}
------>序列化:{}

情况2

添加@Expose注解,等同于 @Expose(deserialize = true,serialize = true)

public class GsonTest5 {
    public static class User {
        @Expose //等同于 @Expose(deserialize = true,serialize = true)
        public String name;
 
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
 
    public static void main(String[] args) throws Exception {
        String jsonFromServer = "{\"name\": \"zhangsan\"}";
        Gson gson = new GsonBuilder()
                .excludeFieldsWithoutExposeAnnotation()
                .create();
        User user = gson.fromJson(jsonFromServer, User.class);
        System.out.println("------>反序列化:" + user);
 
        User user1 = new User();
        user1.name = "zhangsan2";
        String userStr = gson.toJson(user1);
        System.out.println("------>序列化:" + userStr);
    }
}

运行结果:

------>反序列化:User{name='zhangsan'}
------>序列化:{"name":"zhangsan2"}

情况3

只可序列化:@Expose(deserialize = false,serialize = true)

public class GsonTest5 {
    public static class User {
        @Expose(deserialize = false,serialize = true)
        public String name;
 
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
 
    public static void main(String[] args) throws Exception {
        String jsonFromServer = "{\"name\": \"zhangsan\"}";
        Gson gson = new GsonBuilder()
                .excludeFieldsWithoutExposeAnnotation()
                .create();
        User user = gson.fromJson(jsonFromServer, User.class);
        System.out.println("------>反序列化:" + user);
 
        User user1 = new User();
        user1.name = "zhangsan2";
        String userStr = gson.toJson(user1);
        System.out.println("------>序列化:" + userStr);
    }
}

运行结果:

------>反序列化:User{name='null'}
------>序列化:{"name":"zhangsan2"}

情况4

只可反序列化 @Expose(deserialize = true, serialize = false)

public class GsonTest5 { 
    public static class User {
        @Expose(deserialize = true, serialize = false)
        public String name;
 
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
 
    public static void main(String[] args) throws Exception {
        String jsonFromServer = "{\"name\": \"zhangsan\"}";
        Gson gson = new GsonBuilder()
                .excludeFieldsWithoutExposeAnnotation()
                .create();
        User user = gson.fromJson(jsonFromServer, User.class);
        System.out.println("------>反序列化:" + user);
 
        User user1 = new User();
        user1.name = "zhangsan2";
        String userStr = gson.toJson(user1);
        System.out.println("------>序列化:" + userStr);
    }
}

运行结果:

------>反序列化:User{name='zhangsan'}
------>序列化:{}

@Since(float v) 版本控制

结合GsonBuilder.setVersion(n)使用,当n>=v时 才会序列化解析

public class GsonTest6 {
    public static class User {
        @Since(2)
        public String name;
 
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
 
    public static void main(String[] args) throws Exception {
        String jsonFromServer = "{\"name\": \"zhangsan\"}";
        Gson gson = new GsonBuilder()
                .setVersion(1)//版本为1
                .create();
        User user1 = gson.fromJson(jsonFromServer, User.class);
        System.out.println("------>反序列化v=1:" + user1);
 
        User user1_1 = new User();
        user1_1.name = "zhangsan2";
        String userStr = gson.toJson(user1_1);
        System.out.println("------>序列化v=1:" + userStr);
 
 
        Gson gson2 = new GsonBuilder()
                .setVersion(2)//版本为2
                .create();
        User user2 = gson2.fromJson(jsonFromServer, User.class);
        System.out.println("------>反序列化v=2:" + user2);
 
        User user2_1 = new User();
        user2_1.name = "zhangsan2";
        String userStr2_1 = gson2.toJson(user2_1);
        System.out.println("------>序列化v=2:" + userStr2_1);
 
        Gson gson3 = new GsonBuilder()
                .setVersion(3)//版本为3
                .create();
        User user3 = gson3.fromJson(jsonFromServer, User.class);
        System.out.println("------>反序列化v=3:" + user3);
 
        User user3_1 = new User();
        user3_1.name = "zhangsan2";
        String userStr3_1 = gson3.toJson(user3_1);
        System.out.println("------>序列化v=3:" + userStr3_1);
    }
}

运行结果:

------>反序列化v=1:User{name='null'}
------>序列化v=1:{}
------>反序列化v=2:User{name='zhangsan'}
------>序列化v=2:{"name":"zhangsan2"}
------>反序列化v=3:User{name='zhangsan'}
------>序列化v=3:{"name":"zhangsan2"}

@Util(float v) 版本控制

结合GsonBuilder.setVersion(n)使用,当n<时 才会序列化解析

public class GsonTest6 { 
    public static class User {
        @Until(2)
        public String name;
 
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
 
    public static void main(String[] args) throws Exception {
        String jsonFromServer = "{\"name\": \"zhangsan\"}";
        Gson gson = new GsonBuilder()
                .setVersion(1)//版本为1
                .create();
        User user1 = gson.fromJson(jsonFromServer, User.class);
        System.out.println("------>反序列化v=1:" + user1);
 
        User user1_1 = new User();
        user1_1.name = "zhangsan2";
        String userStr = gson.toJson(user1_1);
        System.out.println("------>序列化v=1:" + userStr);
 
 
        Gson gson2 = new GsonBuilder()
                .setVersion(2)//版本为2
                .create();
        User user2 = gson2.fromJson(jsonFromServer, User.class);
        System.out.println("------>反序列化v=2:" + user2);
 
        User user2_1 = new User();
        user2_1.name = "zhangsan2";
        String userStr2_1 = gson2.toJson(user2_1);
        System.out.println("------>序列化v=2:" + userStr2_1);
 
        Gson gson3 = new GsonBuilder()
                .setVersion(3)//版本为3
                .create();
        User user3 = gson3.fromJson(jsonFromServer, User.class);
        System.out.println("------>反序列化v=3:" + user3);
 
        User user3_1 = new User();
        user3_1.name = "zhangsan2";
        String userStr3_1 = gson3.toJson(user3_1);
        System.out.println("------>序列化v=3:" + userStr3_1);
    }
}

运行结果:

------>反序列化v=1:User{name='zhangsan'}
------>序列化v=1:{"name":"zhangsan2"}
------>反序列化v=2:User{name='null'}
------>序列化v=2:{}
------>反序列化v=3:User{name='null'}
------>序列化v=3:{}

Gson 高级用法

TypeAdapter

据说使用TypeAdapter 效率更高。
在TypeAdapter源码中备注了一句 Converts Java objects to and from JSON 就是对象json之间的互相转换,接替了T 泛型类的序列化和反序列化的逻辑。

从源码中我们看到区分了2.1版本之前和之后的用法:

2.1版本之前可以自定义adapter:

public class PointAdapter extends TypeAdapter<Point> {
    public Point read(JsonReader reader) throws IOException {
        if (reader.peek() == JsonToken.NULL) {
            reader.nextNull();
            return null;
        }
        String xy = reader.nextString();
        String[] parts = xy.split(",");
        int x = Integer.parseInt(parts[0]);
        int y = Integer.parseInt(parts[1]);
        return new Point(x, y);
    }

    public void write(JsonWriter writer, Point value) throws IOException {
        if (value == null) {
            writer.nullValue();
            return;
        }
        String xy = value.getX() + "," + value.getY();
        writer.value(xy);
    }
}

使用

GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Point.class, new PointAdapter());
// if PointAdapter didn't check for nulls in its read/write methods, you should instead use
// builder.registerTypeAdapter(Point.class, new PointAdapter().nullSafe());
...
Gson gson = builder.create();

在2.1版本之后更推荐直接插入泛型就使用

//   String json = "{'origin':'0,0','points':['1,2','3,4']}";
//   TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class);
//   Graph graph = graphAdapter.fromJson(json);
// }</pre>
// And an example for serialization: <pre>   {@code
//
//   Graph graph = new Graph(...);
//   TypeAdapter<Graph> graphAdapter = gson.getAdapter(Graph.class);
//   String json = graphAdapter.toJson(graph);
// }</pre>

实例:使用TypeAdapter 来序列化和反序列化

User user = new User();
user.name = "xuanyouwu";
user.age = 26;

Gson gson = new Gson();
TypeAdapter<User> userTypeAdapter = gson.getAdapter(User.class);

String userJsonStr = userTypeAdapter.toJson(user);
System.out.println("------>序列化:" + userJsonStr);

User user1 = userTypeAdapter.fromJson(userJsonStr);
System.out.println("------>反序列化:" + user1);

运行结果:

------>序列化:{"name":"xuanyouwu","age":26}
------>反序列化:User{name='xuanyouwu', age=26}

Gson的容错机制

为什么要容错了?
比如在javaBean中声明了int类型的age,如果服务端返回的是"" 空字符串怎么办呢?
如果json格式不规范如 {name=zhangsan,age:26,hobby=null} 发现不是普通的key value。

1. new GsonBuilder().setLenient()

创建Gson的方式

  gson = new GsonBuilder()
                    .setLenient()// json宽松
                    .create();

2. 使用JsonReader

   JsonReader jsonReader = gson.newJsonReader(value.charStream());
   jsonReader.setLenient(true)

3. 自定义TypeAdapter

4. 使用注解JsonAdapter

其实也是自定义Adapter

1、2归为一类:
由框架实现,基本json大格式规范,键值对不标准,多引号的问题等等,而不报错停止解析,但是功能相对较弱
能解决如下bug:

com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Use JsonReader.setLenient(true) to accept malformed JSON 

3、4归为一类:
都属于自定义adapter,但是3与gson绑定,4使用注解和字段绑定。

实例

public class GsonTest {

    public static class UserTypeAdapter extends TypeAdapter<User> {

        @Override
        public void write(JsonWriter out, User value) throws IOException {
            out.beginObject();
            out.name("name").value(value.name);
            out.name("age").value(value.age);
            out.endObject();
        }

        @Override
        public User read(JsonReader in) throws IOException {
            User user = new User();
            in.beginObject();
            while (in.hasNext()) {
                switch (in.nextName()) {
                    case "name":
                        user.name = in.nextString();
                        break;
                    case "age":
                        try {
                            String str = in.nextString();
                            user.age = Integer.valueOf(str);
                        } catch (Exception e) {
                        }
                        break;
                }
            }
            in.endObject();
            return user;
        }
    }

    public static void main(String[] args) throws Exception {
        String jsonStrFromServer = "{\n" +
                "    \"age\": \"\",\n" +
                "    \"name\": \"zhangsan\"\n" +
                "}";
        System.out.println("------->jsonFromServer:" + jsonStrFromServer);

        Gson gson = new Gson();
        try {
            User user = gson.fromJson(jsonStrFromServer, User.class);
            System.out.println("------>默认Gson 解析:" + user);
        } catch (JsonParseException e) {//java.lang.NumberFormatException: empty String
            System.out.println("------>默认Gson 解析 异常:" + e);
        }

        Gson gson2 = new GsonBuilder()
                .registerTypeAdapter(User.class, new UserTypeAdapter()).create();
        try {
            User user2 = gson2.fromJson(jsonStrFromServer, User.class);
            System.out.println("------>自定义adapter 解析:" + user2);
        } catch (JsonParseException e) {//java.lang.NumberFormatException: empty String
            System.out.println("------>自定义adapter 异常:" + e);
        }

        UserTypeAdapter userTypeAdapter = new UserTypeAdapter();
        try {
            User user3 = userTypeAdapter.fromJson(jsonStrFromServer);
            System.out.println("------>自定义adapter 解析2:" + user3);
        } catch (Exception e) {
            System.out.println("------>自定义adapter 异常2:" + e);
        }
    }

    public static class User {
        public String name;
        public int age;

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
}

运行结果:

------->jsonFromServer:{
    "age": "",
    "name": "zhangsan"
}
------>默认Gson 解析 异常:com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String
------>自定义adapter 解析:User{name='zhangsan', age=0}
------>自定义adapter 解析2:User{name='zhangsan', age=0}

可以看到 age是空字符串 但是不影响整体的解析流程,这对客户端是十分友好的

实例:基于注解的方式

上面的方式倾向于整体,注解的方式倾向于字段。

public class GsonTest {

    public static class User {
        public String name;
        
        @JsonAdapter(IntegerTypeAdapter.class)
        public int age;

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

    public static class IntegerTypeAdapter extends TypeAdapter<Integer> {

        @Override
        public void write(JsonWriter out, Integer value) throws IOException {
            out.value(value);
        }

        @Override
        public Integer read(JsonReader in) throws IOException {
            int i = 0;
            try {
                String str = in.nextString();
                i = Integer.valueOf(str);
            } catch (Exception e) {
            }
            return i;
        }
    }

    public static class User2 {
        public String name;
        public int age;

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }


    public static void main(String[] args) throws Exception {
        String jsonStrFromServer = "{\n" +
                "    \"age\": \"\",\n" +
                "    \"name\": \"zhangsan\"\n" +
                "}";
        System.out.println("------->jsonFromServer:" + jsonStrFromServer);

        Gson gson = new Gson();
        try {
            User2 user2 = gson.fromJson(jsonStrFromServer, User2.class);
            System.out.println("------>gson 解析:" + user2);
        } catch (Exception e) {
            System.out.println("------>gson 解析异常:" + e);
        }


        try {
            User user = gson.fromJson(jsonStrFromServer, User.class);
            System.out.println("------>JsonAdapter 注解 解析:" + user);
        } catch (JsonParseException e) {//java.lang.NumberFormatException: empty String
            System.out.println("------>JsonAdapter 注解 异常:" + e);
        }
    }
}

运行结果:

------->jsonFromServer:{
    "age": "",
    "name": "zhangsan"
}
------>gson 解析异常:com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String
------>JsonAdapter 注解 解析:User{name='zhangsan', age=0}

可以看到我们成功地跳过服务端返回json不合理的坑了吧。

5. JsonDeserializer

其实上面的方式保险是很保险,但是需要维护的地方多,代码量大,我们介绍另外一种方式:JsonSerializer与JsonDeserializer 之关系单方面的处理,可以全局注册某个类型的处理
看实例:

public class GsonTest {

    public static void main(String[] args) throws Exception {
        JsonDeserializer<Integer> jsonDeserializer = new JsonDeserializer<Integer>() {
            @Override
            public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
                    throws JsonParseException {
                try {
                    return json.getAsInt();
                } catch (NumberFormatException e) {
                    return 0;
                }
            }
        };

        String jsonStrFromServer = "{\n" +
                "    \"age\": \"\",\n" +
                "    \"name\": \"zhangsan\"\n" +
                "}";
        System.out.println("------->jsonFromServer:" + jsonStrFromServer);

        Gson gson = new GsonBuilder()
                .registerTypeAdapter(int.class, jsonDeserializer)
                .create();
        try {
            User user = gson.fromJson(jsonStrFromServer, User.class);
            System.out.println("------>  JsonDeserializer<Integer> 解析:" + user);
        } catch (Exception e) {
            System.out.println("------>  JsonDeserializer<Integer> 解析异常:" + e);
        }

        Gson gson1 = new Gson();
        try {
            User user1 = gson1.fromJson(jsonStrFromServer, User.class);
            System.out.println("------> 默认gson 解析:" + user1);
        } catch (Exception e) {
            System.out.println("------>  默认gson 解析异常:" + e);
        }


    }

    public static class User {
        public String name;
        public int age;

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
}

运行结果:

------->jsonFromServer:{
    "age": "",
    "name": "zhangsan"
}
------>  JsonDeserializer<Integer> 解析:User{name='zhangsan', age=0}
------>  默认gson 解析异常:com.google.gson.JsonSyntaxException: java.lang.NumberFormatException: empty String

这样定义全局的反序列化工具就能避免解析异常

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

推荐阅读更多精彩内容