一、概述
Gson是google提供的用来操作json数据的一个非常好用的类库。其使用范围非常的广泛,所以非常有必要对其进行系统的学习。
json是一种数据格式,确切的说是一种文本数据格式。其在网络通讯过程中的作用非常的明显。
目前大多数的网络通讯格式已经从xml替换为json格式。
其提供了序列化和反序列化的功能。在我们进行网络开发的过程中通常会把参数封装成json格式传给后台,后台解析后的返回结果也会封装成json格式返回给调用者。
1.如何创建一个Gson对象
/*** 创建Gson对象的两种形式*/private void createGsonObject() {//第一种方式Gson gson = new Gson();//第二种方式Gson gson1 = new GsonBuilder().create();//方式二除了可以创建一个Gson对象以外还可以进行多项配置,例如,设置日期的格式化
// 例如: new GsonBuilder().setDateFormat("yyyy-MM-dd");}
2.如何创建一个JsonObject
/*** 如何创建一个json对象*/private void createJsonObject() {JsonObject jsonObject = new JsonObject();jsonObject.addProperty("id", "1");//给jsonObject创建一个id属性值为1jsonObject.addProperty("bookName", "《深入Java虚拟机》");jsonObject.addProperty("bookPrice", 36.8);jsonObject.addProperty("bookColor", "红色");//打印Json字符串System.out.println(jsonObject.toString());//给JsonObject添加对象JsonObject jsonObject1 = new JsonObject();jsonObject1.addProperty("chapterId", "1");jsonObject1.addProperty("chapterName", "第一章");//给JsonObject添加实体对象jsonObject.add("chapter", jsonObject1);System.out.println(jsonObject.toString());/*** 输出结果:* {"id":"1","bookName":"《深入Java虚拟机》","bookPrice":36.8,"bookColor":"红色"}* {"id":"1","bookName":"《深入Java虚拟机》","bookPrice":36.8,"bookColor":"红色","chapter":{"chapterId":"1","chapterName":"第一章"}}*/}
注:这里的JsonObject表示我们一样可以创建一个json对象;但是我们后面一般使用的是java对象跟json字符串的转换,可以用通过创建好的gson对象来操作。
3.数组的序列化与反序列化
/*** 根据一个json创建一个数组*/private void createJsonArray() {//把数组转换为Json字符串String[] str = new String[]{"《深入Java虚拟机》", "《Android插件编程》", "《OpenCV全解》"};Gson gson = new Gson();String jsonStr = gson.toJson(str);//先创建一个Json字符串System.out.println(jsonStr);//输出//把Json字符串转换为Json数组String[] strArray = gson.fromJson(jsonStr, String[].class);for (String s : strArray) {System.out.println(s);}/*** 输出结果:* ["《深入Java虚拟机》","《Android插件编程》","《OpenCV全解》"]* 《深入Java虚拟机》* 《Android插件编程》* 《OpenCV全解》*/}
4.List的序列化与反序列化
/*** 根据一个json创建一个list*/private void createJsonToList() {//将list集合转换为json字符串List<Book> books = new ArrayList<>();books.add(new Book("1", "《深入Java虚拟机》"));books.add(new Book("2", "《OpenCV进阶》"));books.add(new Book("3", "《深入Android源代码》"));Gson gson = new Gson();String jsonListStr = gson.toJson(books);System.out.println(jsonListStr);//将json字符串转换为list集合//获取泛型的类型Type type = new TypeToken<List<Book>>() {}.getType();//使用gson将字符串转换为泛型集合,即List<Book>List<Book> books1 = gson.fromJson(jsonListStr, type);for (Book book : books1) {System.out.println(book.getName());}/*** 输出结果:* [{"id":"1","name":"《深入Java虚拟机》"},{"id":"2","name":"《OpenCV进阶》"},{"id":"3","name":"《深入Android源代码》"}]* 《深入Java虚拟机》* 《OpenCV进阶》* 《深入Android源代码》*/}
注:
//获取泛型的类型
Type type = new TypeToken<List<Book>>() {}.getType();*
5.序列化与反序列化综合例子(基于Book对象)
public class Book {public Book(){}private String id;/*** 加上@SerializedName注解后服务端api返回bookName、Name、bn时,客户端都能够拿到正确的值给name属性。*/@SerializedName(value = "bookName",alternate = {"Name","bn"})private String name;public Book(String id, String name) {this.id = id;this.name = name;}
}/*** json的序列化与反序列化* 使用toJson实现序列化,使用fromJson实现反序列化*/private void jsonSeriaReSeria() {Gson gson = new Gson();Book book = new Book("1", "《深入Java虚拟机》");//将book类序列化成字符串String bookStr = gson.toJson(book);System.out.println(bookStr);//将bookStr反序列化成为Book类Book b = gson.fromJson(bookStr, Book.class);System.out.println(b.getName());}
6.如何为属性做兼容性处理(重命名、预设名称等)
/*** 如何给json属性重命名* 假设我们有这样一个需求:由于接口改版,从服务端返回的api中的book字段的name属性,变为了bookName。如果我们* 仍然用name进行解析,则接不到bookName的值,而由于服务端没有返回name,则解析后name=null。如果要考虑到兼容性那么我们的的Book类的属性就* 需要做一下兼容性的处理。* 使用@SerializedName可以给属性重命名。用@SerializedName的alternate属性给Book的属性做扩展*/private void reNameProperty() {String bookJson = "{\"id\":\"1\",\"bookName\":\"《深入Java虚拟机》\"}";Gson gson = new Gson();Book book = gson.fromJson(bookJson, Book.class);System.out.println(book.getName());}
注:@SerializedName(value = “bookName”,alternate = {“Name”,“bn”})表示在反序列化时候可以使用bookName,Name,bn都可以被识别到,set到Book中的name属性;相应的在序列化的时候,name属性会被序列化为bookName字符串;
7.GsonBuilder的一些基础配置
/*** 对GsonBuilder一些属性介绍*/private void gsonBuilderProperty() {Gson gson = new GsonBuilder().serializeNulls()//默认情况下如果某一个属性为null,那么此属性不会参与序列化和反序列化的过程,加上此属性后会参与序列化和反序列化的过程.setPrettyPrinting()//格式化json字符串的输出,默认情况下是输出一行,经过这个属性设置后会格式化输出,即有缩进的输出.setDateFormat("yyyy-MM-dd HH:mm:ss")//对时间进行格式化.create();}
8.TypeAdapter使用方法介绍
/*** typeAdapter的使用方法* TypeAdapter是一个泛型抽象类,用于接管某种类型的序列化和反序列化的过程* 它包含两个抽象方法write和read,分别用于自定义的序列化和反序列化的过程*/private void useTypeAdapter() {Gson gson = new GsonBuilder().registerTypeAdapter(Book.class,new BookTypeAdapter()).create();Book book = new Book("1","深入Java虚拟机");System.out.println(gson.toJson(book));String bookJson = "{\"Id\":\"1\",\"Name\":\"《深入Java虚拟机》\"}";Book book1 = gson.fromJson(bookJson,Book.class);System.out.println(gson.toJson(book1));}以下是BookTypeAdapter的代码介绍package com.yw.gsonlib;import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;import java.io.IOException;public class BookTypeAdapter extends TypeAdapter<Book> {/*** 序列化接口** @param jsonWriter* @param book* @throws IOException*/@Overridepublic void write(JsonWriter jsonWriter, Book book) throws IOException {//流式序列化对象开始jsonWriter.beginObject();//将Json的key值都指定为首字母大写jsonWriter.name("Id").value(book.getId());jsonWriter.name("Name").value(book.getName());//流式序列化对象结束jsonWriter.endObject();}/*** 反序列化接口** @param jsonReader* @return* @throws IOException*/@Overridepublic Book read(JsonReader jsonReader) throws IOException {Book book = new Book();//流式反序列化开始jsonReader.beginObject();while (jsonReader.hasNext()) {switch (jsonReader.nextName()) {case "id":case "Id":book.setId(jsonReader.nextString());break;case "name":case "Name":book.setName(jsonReader.nextString());break;}}//流式反序列化结束jsonReader.endObject();return book;}
}
Gson 工具类
package com.utils;import com.google.gson.*;
import com.google.gson.reflect.TypeToken;import java.util.ArrayList;
import java.util.List;
import java.util.Map;public class GsonUtils {//不用创建对象,直接使用Gson.就可以调用方法private static Gson gson = null;//判断gson对象是否存在了,不存在则创建对象static {if (gson == null) {//gson = new Gson();// 当使用GsonBuilder方式时属性为空的时候输出来的json字符串是有键值key的,显示形式是"key":null,而直接new出来的就没有"key":null的gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();}}//无参的私有构造方法private GsonUtils() {}/*** 将对象转成json格式** @param object* @return String*/public static String GsonString(Object object) {String gsonString = null;if (gson != null) {gsonString = gson.toJson(object);}return gsonString;}/*** 将json转成特定的cls的对象** @param gsonString* @return*/public static <T> T GsonToBean(String gsonString, Class<T> cls) {T t = null;if (gson != null) {//传入json对象和对象类型,将json转成对象t = gson.fromJson(gsonString, cls);}return t;}/*** json字符串转成list** @param gsonString* @return*/public static <T> List<T> GsonToList(String gsonString, Class<T> cls) {List<T> list = null;if (gson != null) {//根据泛型返回解析指定的类型,TypeToken<List<T>>{}.getType()获取返回类型list = gson.fromJson(gsonString, new TypeToken<List<T>>() {}.getType());}return list;}/*** json字符串转成list** @param json* @return*/public static <T> List<T> jsonToList(String json, Class<T> cls) {ArrayList<T> mList = new ArrayList<T>();JsonArray array = new JsonParser().parse(json).getAsJsonArray();for (final JsonElement elem : array) {mList.add(gson.fromJson(elem, cls));}return mList;}/*** json字符串转成数组** @param json* @return*/public static Object[] json2ObjectArray(String json, Class cls) {TypeToken<?> array = TypeToken.getArray(cls);Gson gson = new Gson();Object[] objects = gson.fromJson(json, array.getType());return objects;}/*** json字符串转成list中有map的** @param gsonString* @return*/public static <T> List<Map<String, T>> GsonToListMaps(String gsonString) {List<Map<String, T>> list = null;if (gson != null) {list = gson.fromJson(gsonString,new TypeToken<List<Map<String, T>>>() {}.getType());}return list;}/*** json字符串转成map的** @param gsonString* @return*/public static <T> Map<String, T> GsonToMaps(String gsonString) {Map<String, T> map = null;if (gson != null) {map = gson.fromJson(gsonString, new TypeToken<Map<String, T>>() {}.getType());}return map;}
}
注意:
项目中要求不要使用Fastjson,原因:Fastjson存在安全漏洞
经查阅资料:Fastjson≤1.2.80的版本存在安全漏洞;
Gson工具类
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import lombok.SneakyThrows;import java.lang.reflect.Type;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Objects;public class GsonUtils {private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");private static final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");private static final JsonSerializer<LocalDateTime> dateTimeSerializer= (obj, type, ctx) -> new JsonPrimitive(dateTimeFormatter.format(obj));private static final JsonSerializer<LocalDate> dateSerializer= (obj, type, ctx) -> new JsonPrimitive(dateFormatter.format(obj));private static final JsonSerializer<LocalTime> timeSerializer= (obj, type, ctx) -> new JsonPrimitive(timeFormatter.format(obj));private static final JsonDeserializer<LocalDateTime> dateTimeDeserializer= (json, type, ctx) -> LocalDateTime.parse(json.getAsJsonPrimitive().getAsString(), dateTimeFormatter);private static final JsonDeserializer<LocalDate> dateDeserializer= (json, type, ctx) -> LocalDate.parse(json.getAsJsonPrimitive().getAsString(), dateFormatter);private static final JsonDeserializer<LocalTime> timeDeserializer= (json, type, ctx) -> LocalTime.parse(json.getAsJsonPrimitive().getAsString(), timeFormatter);private static final Gson gson;static {GsonBuilder builder = new GsonBuilder();builder.disableHtmlEscaping();builder.enableComplexMapKeySerialization();// builder.excludeFieldsWithoutExposeAnnotation();builder.setDateFormat("yyyy-MM-dd HH:mm:ss");builder.registerTypeAdapter(LocalDateTime.class, dateTimeSerializer);builder.registerTypeAdapter(LocalDate.class, dateSerializer);builder.registerTypeAdapter(LocalTime.class, timeSerializer);builder.registerTypeAdapter(LocalDateTime.class, dateTimeDeserializer);builder.registerTypeAdapter(LocalDate.class, dateDeserializer);builder.registerTypeAdapter(LocalTime.class, timeDeserializer);gson = builder.create();}public static Type makeJavaType(Type rawType, Type... typeArguments) {return TypeToken.getParameterized(rawType, typeArguments).getType();}public static String toString(Object value) {if (Objects.isNull(value)) {return null;}if (value instanceof String) {return (String) value;}return toJSONString(value);}public static String toJSONString(Object value) {return gson.toJson(value);}public static String toPrettyString(Object value) {return gson.newBuilder().setPrettyPrinting().create().toJson(value);}public static JsonElement fromJavaObject(Object value) {JsonElement result = null;if (Objects.nonNull(value) && (value instanceof String)) {result = parseObject((String) value);} else {result = gson.toJsonTree(value);}return result;}@SneakyThrowspublic static JsonElement parseObject(String content) {return JsonParser.parseString(content);}public static JsonElement getJsonElement(JsonObject node, String name) {return node.get(name);}public static JsonElement getJsonElement(JsonArray node, int index) {return node.get(index);}@SneakyThrowspublic static <T> T toJavaObject(JsonElement node, Class<T> clazz) {return gson.fromJson(node, clazz);}@SneakyThrowspublic static <T> T toJavaObject(JsonElement node, Type type) {return gson.fromJson(node, type);}public static <T> T toJavaObject(JsonElement node, TypeToken<?> typeToken) {return toJavaObject(node, typeToken.getType());}public static <E> List<E> toJavaList(JsonElement node, Class<E> clazz) {return toJavaObject(node, makeJavaType(List.class, clazz));}public static List<Object> toJavaList(JsonElement node) {return toJavaObject(node, new TypeToken<List<Object>>(){}.getType());}public static <V> Map<String, V> toJavaMap(JsonElement node, Class<V> clazz) {return toJavaObject(node, makeJavaType(Map.class, String.class, clazz));}public static Map<String, Object> toJavaMap(JsonElement node) {return toJavaObject(node, new TypeToken<Map<String, Object>>(){}.getType());}@SneakyThrowspublic static <T> T toJavaObject(String content, Class<T> clazz) {return gson.fromJson(content, clazz);}@SneakyThrowspublic static <T> T toJavaObject(String content, Type type) {return gson.fromJson(content, type);}public static <T> T toJavaObject(String content, TypeToken<?> typeToken) {return toJavaObject(content, typeToken.getType());}public static <E> List<E> toJavaList(String content, Class<E> clazz) {return toJavaObject(content, makeJavaType(List.class, clazz));}public static List<Object> toJavaList(String content) {return toJavaObject(content, new TypeToken<List<Object>>(){}.getType());}public static <V> Map<String, V> toJavaMap(String content, Class<V> clazz) {return toJavaObject(content, makeJavaType(Map.class, String.class, clazz));}public static Map<String, Object> toJavaMap(String content) {return toJavaObject(content, new TypeToken<Map<String, Object>>(){}.getType());}}