From 4de571cb6d218b82de873bad2f679270512ba794 Mon Sep 17 00:00:00 2001 From: wu xiangkai Date: Tue, 23 Aug 2022 15:45:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=97=A5=E5=B8=B8=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spring/json/gson/gson.md | 106 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) diff --git a/spring/json/gson/gson.md b/spring/json/gson/gson.md index 29b228b..16c7e62 100644 --- a/spring/json/gson/gson.md +++ b/spring/json/gson/gson.md @@ -56,4 +56,108 @@ String json = gson.toJson(obj); // Deserialization BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class); // ==> obj2 is just like obj -``` \ No newline at end of file +``` +### gson和对象联用的使用规范 +- gson使用过程中,待序列化或反序列化的成员字段可以是private的,同时也推荐将待序列化或反序列化的成员字段声明为private +- 没有必要对成员字段使用注解来特定标明在序列化或者反序列化中包含该字段,默认情况下该对象所有成员字段和该对象父类对象所包含的所有字段都会被序列化 +- 类似于jdk自带的序列化和反序列化机制,如果一个字段被标明为transient,该字段将不会被包含到序列化和反序列化过程中 +- gson实现能够正确处理字段为空的情况 + - 当序列化过程中,为null的字段将会被省略 + - 当反序列化过程中,如果一个字段在json串中并没有被设置,反序列化得到的对象中该字段将会被设置为默认值:引用类型默认值为null、数字类型默认值为0,boolean类型其默认值为false +- 在内部类、匿名类、本地类中关联外部类的字段将会被忽略,并不会包含在序列化和反序列化过程中 +### gson和嵌套类的关联使用 +gson可以单独的对静态内部类进行序列化和反序列化,因为静态内部类并不包含对外部类的引用;但是gson无法单独的反序列化内部类,因为在反序列化内部类的过程中,其无参构造器需要一个指向其外部类对象的引用,但是该外部类对象在对内部类进行反序列化时是不可访问的。 +可以通过将内部类改为静态的内部类,此时对内部类的反序列化将不会需要指向外部类对象的引用。 +### gson和数组的关联使用 +gson支持多维数组,并且支持任意的复杂元素类型 +```java +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 +``` +### gson对java中的集合进行序列化和反序列化 +gson可以序列化任意对象的集合,但是无法对其进行反序列化,因为在反序列化时用户没有任何方法去指定其生成的集合中元素的类型。因而,需要通过typeToken来告知Gson需要反序列化的类型。 +```java +Gson gson = new Gson(); +Collection ints = Arrays.asList(1,2,3,4,5); + +// Serialization +String json = gson.toJson(ints); // ==> json is [1,2,3,4,5] + +// Deserialization +Type collectionType = new TypeToken>(){}.getType(); +Collection ints2 = gson.fromJson(json, collectionType); +// ==> ints2 is same as ints +``` +### gson对Map类型的序列化和反序列化 +默认情况下,gson会将java中任意的Map实现类型序列化为JSON对象。由于JSON对象其key只支持字符串类型,gson会将待序列化的Map key调用toString转化为字符串。如果map中的key为null,则序列化后的key为"null" +```java +/** + * gson对map进行序列化 + **/ +Gson gson = new Gson(); +Map stringMap = new LinkedHashMap<>(); +stringMap.put("key", "value"); +stringMap.put(null, "null-entry"); + +// Serialization +String json = gson.toJson(stringMap); // ==> json is {"key":"value","null":"null-entry"} + +Map intMap = new LinkedHashMap<>(); +intMap.put(2, 4); +intMap.put(3, 6); + +// Serialization +String json = gson.toJson(intMap); // ==> json is {"2":4,"3":6} +``` +在反序列化的过程中,gson会使用为Map key类型注册的TypeAdapter的read方法来进行反序列化。为了让gson知道反序列化得到的Map对象的key和value类型,需要使用TypeToken。 +```java +Gson gson = new Gson(); +Type mapType = new TypeToken>(){}.getType(); +String json = "{\"key\": \"value\"}"; + +// Deserialization +Map stringMap = gson.fromJson(json, mapType); +// ==> stringMap is {key=value} +``` +默认情况下,gson序列化map时,复杂类型的key会调用toString方法来将其转化成字符串。但是,gson同样支持开启复杂类型key的序列化操作。通过Gson.enableComplexMapKeySerialization()方法来开启,Gson会调用为Map的key类型注册的TypeAdapter的write方法来序列化key,而不是通过toString方法将key转化为字符串。 +> 当Map中任意一条Entry的key通过Adapter被序列化为了JSON数组或者对象,那么Gson会将整个Map序列化为Json数组,数组元素为map中entry的键值对。如果map中所有的entry key都不会被序列化为json object或json array,那么该map将会被序列化为json对象 + +> 在对枚举型key进行反序列化的过程中,如果enum找不到一个具有匹配name()值的常量时,其会采用一个回退机制,根据枚举常量的toString()值来进行反序列化的匹配。 + +### 序列化和反序列化泛型对象 +当gson对object对象调用toJson方法时,gson会调用object.getClass()来获取需要序列化的字段信息。类似的,在gson调用fromJson时,会向fromJson方法传递一个MyClass.class对象。该方法在序列化和反序列化类型是非泛型类型时能够正常运行。 +但是,当待序列化和反序列化的类型是泛型类型时,在序列化和反序列化对象时泛型类型信息会丢失,因为泛型采用的是类型擦除。 +```java +class Foo { + T value; +} +Gson gson = new Gson(); +Foo foo = new Foo(); +gson.toJson(foo); // May not serialize foo.value correctly + +gson.fromJson(json, foo.getClass()); // Fails to deserialize foo.value as Bar +``` +> 上述代码中,foo.getClass()方法返回的只是Foo.class对象,并不会包含泛型类型Bar的信息,故而在反序列化时gson并不知道应该将value反序列化为Bar类型 + +可以通过向fromJson中传入Type参数来详细指定想要将json串转化成的泛型类型信息 +```java +Type fooType = new TypeToken>() {}.getType(); +gson.toJson(foo, fooType); + +gson.fromJson(json, fooType); +``` +### 序列化和反序列化集合,集合中保存任意类型的对象 +当JSON串中数组包含各种类型元素时,将其转化为包含任意类型的java集合,可以有如下方法: +- 使用Gson Parser API(JsonParser,底层parser api)将json串中数组转化为JsonArray,并且为每个元素调用Gson.fromJson。该方法是推荐的方法 +> gson.fromJson可以针对String、Reader、JsonElement来调用 + +