Java中最常用的json类库有:JSON-Java、Gson、Jackson、FastJson等
github地址:https://github.com/google/gson
1. Gson对象
在进行序列化与反序列操作前,需要先实例化一个 com .google.gson.Gson 对象,获取 Gson 对象的方法有两种
//通过构造函数来获取
Gson gson = new Gson();
//通过 GsonBuilder 来获取,可以进行多项特殊配置
Gson gson = new GsonBuilder().create();
2. 生成 Json
利用 Gson 可以很方便地生成 Json 字符串,通过使用 addProperty 的四个重载方法
public static void main(String[] args) {
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("String", "leavesC");
jsonObject.addProperty("Number_Integer", 23);
jsonObject.addProperty("Number_Double", 22.9);
jsonObject.addProperty("Boolean", true);
jsonObject.addProperty("Char", 'c');
System.out.println(jsonObject);
}
3. Json与数组、List的转化
3.1 Json数组 与 字符串数组
public static void main(String[] args) {
Gson gson = new Gson();
//Json数组 转为 字符串数组
String jsonArray = "[\"https://github.com/leavesC\",\"https://www.jianshu.com/u/9df45b87cfdf\",\"Java\",\"Kotlin\",\"Git\",\"GitHub\"]";
String[] strings = gson.fromJson(jsonArray, String[].class);
//字符串数组 转为 Json数组
jsonArray = gson.toJson(jsonArray, new TypeToken<String>() {}.getType());
System.out.println(jsonArray);
}
3.2 Json数组 与 List
对于List将上面的代码中的 String[].class 直接改为 List<String>.class 是不行的,对于Java来说List<String> 和List<User> 这俩个的字节码文件只一个那就是List.class,这是Java泛型使用时要注意的问题【泛型擦除】。为了解决的上面的问题,Gson提供了TypeToken来实现对泛型的支持,所以将以上的数据解析为List<String>时需要这样写
public static void main(String[] args) {
Gson gson = new Gson();
String jsonArray = "[\"https://github.com/leavesC\",\"https://www.jianshu.com/u/9df45b87cfdf\",\"Java\",\"Kotlin\",\"Git\",\"GitHub\"]";
//Json数组 转为 List
List<String> stringList = gson.fromJson(jsonArray, new TypeToken<List<String>>() {}.getType());
//List 转为 Json数组
jsonArray = gson.toJson(stringList, new TypeToken<List<String>>() {}.getType());
}
4.POJO类的生成与解析
//生成JSON
Gson gson = new Gson();
User user = new User("张三",24);
String jsonObject = gson.toJson(user); // {"name":"张三kidou","age":24}
//解析JSON
Gson gson = new Gson();
String jsonString = "{\"name\":\"张三\",\"age\":24}";
User user = gson.fromJson(jsonString, User.class);
5. 属性重命名 @SerializedName 注解
从上面POJO的生成与解析可以看出json的字段和值是的名称和类型是一一对应的,但也有一定容错机制(如第一个例子第3行将字符串的99.99转成double型),但有时候也会出现一些不和谐的情况,如:
期望的json格式:{"name":"张三","age":24,"emailAddress":"zhangsan@ceshi.com"}
实际:{"name":"张三","age":24,"email_address":"zhangsan@ceshi.com"}
Gson在序列化和反序列化时需要使用反射,一般各类库都将注解放到annotations包下,打开源码在com.google.gson包下有一个annotations,里面有一个SerializedName的注解类。对于json中email_address这个属性对应POJO的属性则变成:
@SerializedName("email_address")
public String emailAddress;
为POJO字段提供备选属性名:SerializedName注解提供了两个属性,上面用到了其中一个,别外还有一个属性alternate,接收一个String数组
注:alternate需要2.4版本
@SerializedName(value = "emailAddress", alternate = {"email", "email_address"})
public String emailAddress;
//当三个属性(email_address、email、emailAddress)都中出现任意一个时均可以得到正确的结果
//当多种情况同时出时,以最后一个出现的值为准。
Gson gson = new Gson();
String json = "{\"name\":\"张三kidou\",\"age\":24,\"emailAddress\":\"zhangsan@ceshi.com\",\"email\":\"zhangsan_2@ceshi.com\",\"email_address\":\"zhangsan_3@ceshi.com\"}";
User user = gson.fromJson(json, User.class);
System.out.println(user.emailAddress); // zhangsan_3@example.com
6. 使用GsonBuilder导出null值、格式化输出、日期时间
(1)Gson在默认情况下是不动导出值null的键的
Gson gson = new Gson();
User user = new User(张三",24);
System.out.println(gson.toJson(user)); //{"name":"张三","age":24}
//email字段是没有在json中出现的,当在调试时需要导出完整的json串时或API接中要求没有值必须用Null时,就会比较有用。
//使用GsonBuilder
Gson gson = new GsonBuilder().serializeNulls().create();
User user = new User("张三", 24);
System.out.println(gson.toJson(user)); //{"name":"张三","age":24,"email":null}
(2)格式化输出、日期时间及其它
Gson gson = new GsonBuilder()
//序列化null
.serializeNulls()
// 设置日期时间格式,另有2个重载方法
// 在序列化和反序化时均生效
.setDateFormat("yyyy-MM-dd")
// 禁此序列化内部类
.disableInnerClassSerialization()
//生成不可执行的Json(多了 )]}' 这4个字符)
.generateNonExecutableJson()
//禁止转义html标签
.disableHtmlEscaping()
//格式化输出
.setPrettyPrinting()
.create();
//:内部类(Inner Class)和嵌套类(Nested Class)的区别
7. Type解读(附)
Type指java.lang.reflect.Type, 是Java中所有类型的公共高级接口, 代表了Java中的所有类型。
Type体系中类型的包括:数组类型(GenericArrayType)、参数化类型(ParameterizedType)、类型变量(TypeVariable)、通配符类型(WildcardType)、原始类型(Class)、基本类型(Class), 以上这些类型都实现Type接口.
参数化类型,就是我们平常所用到的泛型List、Map;
数组类型,并不是我们工作中所使用的数组String[] 、byte[],而是带有泛型的数组,即T[] ;
通配符类型, 指的是<?>, <? extends T>等等
原始类型, 不仅仅包含我们平常所指的类,还包括枚举、数组、注解等;
基本类型, 也就是我们所说的java的基本类型,即int,float,double等