1、简述
> 番外篇 如何序列化值为null的属性 方式1: new GsonBuilder().serializeNulls().create(); 方式2: 重写相应的 TypeAdapters 解析规则 -- 将null 转换为空字符串 方式3: 自定义 TypeAdapterFactory下面重点介绍方式2 和 方式3
2、方式2 重写TypeAdapters的解析规则
通过new Gson()查看对应的构造器 , Gson的数据解析都是委托到各个TypeAdapter内进行处理的。 在Gson的构造函数内会预先加载一部分TypeAdapter, 包含String、int、long、double等类型,都存放在factories中,如下: 发现都可以通过自定义TypeAdapter解决。 自定义TypeAdapter,将其放入facotries中, 并且gson在解析json时使用对应的TypeAdapter来的, 而我们手动添加的TypeAdapter会优先于预设的TypeAdapter被使用 因此 我们来覆盖 一些常用的包装类型的 null值的序列化 重写自己的TypeAdapters
package sun.rain.amazing.gson.type; import com.google.gson.JsonSyntaxException; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import java.io.IOException; /** * 变成不可被继承的 * @author sunRainAmazing */ public final class TypeAdaptersRedefine { public static final String EMPTY = ""; /** * 对于String 类型 的 策略 */ public static final TypeAdapter<String> STRING = new TypeAdapter<String>() { //进行反序列化 @Override public String read(JsonReader reader) { try { if (reader.peek() == JsonToken.NULL) { reader.nextNull(); return null; } //要进行属性值的判断 若为 空字符串 则返回null 否则返回 本身的值 String result = reader.nextString(); return result.length() > 0 ? result : null; } catch (Exception e) { throw new JsonSyntaxException(e); } } // 进行序列化 @Override public void write(JsonWriter writer, String value) { try { if (value == null) { writer.value(EMPTY); return; } writer.value(value); } catch (Exception e) { e.printStackTrace(); } } }; /** * 对于int 和 Integer 类型 * 由于 int 类型 有默认值 0, * -- 通常我们无法确定 0 是否具备实际意义 * 但是 Integer 的类型 null , 我们可以确定的是 -- 无意义的 * * 因此在设计属性的类型是 通常采用 Integer 而不是 int 类型 * * 故 由于 int 的 0 具备 实际意义 -- 不进行转换 * 而是转换 Integer 类型的 null 值 */ public static final TypeAdapter<Number> INTEGER = new TypeAdapter<Number>() { @Override public Number read(JsonReader in) throws IOException { System.out.println(in.peek() +" ----->"); if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } if (in.peek() == JsonToken.STRING) { in.nextString(); return null; } return in.nextInt(); } @Override public void write(JsonWriter out, Number value) throws IOException { if(value == null){ out.value(EMPTY); }else{ out.value(value); } } }; /** * 对于double类型的转换 */ public static final TypeAdapter<Number> DOUBLE = new TypeAdapter<Number>() { @Override public Number read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } if (in.peek() == JsonToken.STRING) { in.nextString(); return null; } return in.nextDouble(); } @Override public void write(JsonWriter out, Number value) throws IOException { if(value == null){ out.value(EMPTY); }else{ out.value(value); } } }; }
相关测试类
@Data @AllArgsConstructor @NoArgsConstructor public class GsonStrNull1 { private String str; private Integer integer; private Double doubleType; private int intType; public GsonStrNull1(String str) { this.str = str; } public GsonStrNull1(String str, Integer integer) { this.str = str; this.integer = integer; } public GsonStrNull1(String str, Integer integer, Double doubleType) { this.str = str; this.integer = integer; this.doubleType = doubleType; } public GsonStrNull1(Integer integer, Double doubleType, int intType) { this.integer = integer; this.doubleType = doubleType; this.intType = intType; } public GsonStrNull1(Double doubleType, int intType) { this.doubleType = doubleType; this.intType = intType; } public GsonStrNull1(Double doubleType) { this.doubleType = doubleType; } }
测试类
package sun.rain.amazing.gson.strnull; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; import org.junit.Test; import sun.rain.amazing.gson.stringnull.GsonStrNull; import sun.rain.amazing.gson.stringnull.GsonStrNull1; import sun.rain.amazing.gson.stringnull.NullStringToEmptyAdapterFactory; import sun.rain.amazing.gson.type.TypeAdaptersRedefine; /** * @author Reese */ public class GsonTypeAdaptersNullTest { /** * {"str":"tom","integer":12,"doubleType":12.56,"intType":0} * GsonStrNull1(str=tom, integer=12, doubleType=12.56, intType=0) */ @Test public void testNullAll(){ GsonStrNull1 g = new GsonStrNull1("tom",12,12.56); Gson gson = new GsonBuilder() // 进行注册自己的 TypeAdapter .registerTypeAdapter(String.class,TypeAdaptersRedefine.STRING) .registerTypeAdapter(Integer.class,TypeAdaptersRedefine.INTEGER) .registerTypeAdapter(Double.class,TypeAdaptersRedefine.DOUBLE) .create(); //序列化 String json = gson.toJson(g); System.out.println(json); //反序列化 g = gson.fromJson(json, GsonStrNull1.class); System.out.println(g); } @Test public void testNullIntegerAndDouble(){ GsonStrNull1 g = new GsonStrNull1("tom"); Gson gson = new GsonBuilder() // 进行注册自己的 TypeAdapter .registerTypeAdapter(String.class,TypeAdaptersRedefine.STRING) .registerTypeAdapter(Integer.class,TypeAdaptersRedefine.INTEGER) .registerTypeAdapter(Double.class,TypeAdaptersRedefine.DOUBLE) .create(); //序列化 String json = gson.toJson(g); System.out.println(json); //反序列化 g = gson.fromJson(json, GsonStrNull1.class); System.out.println(g); } @Test public void testNullFloat(){ GsonStrNull1 g = new GsonStrNull1("tom",12); Gson gson = new GsonBuilder() // 进行注册自己的 TypeAdapter .registerTypeAdapter(String.class,TypeAdaptersRedefine.STRING) .registerTypeAdapter(Integer.class,TypeAdaptersRedefine.INTEGER) .registerTypeAdapter(Double.class,TypeAdaptersRedefine.DOUBLE) .create(); //序列化 String json = gson.toJson(g); System.out.println(json); //反序列化 json = "{\"str\":\"tom\",\"integer\":12.3}"; g = gson.fromJson(json, GsonStrNull1.class); System.out.println(g); } }
3、方式3 自定义 TypeAdapterFactory
针对String 类型
package sun.rain.amazing.gson.stringnull; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import java.io.IOException; /** * 仅针对于 String 类型的数据 * @author sunRainAmazing */ public class StringNullAdapter extends TypeAdapter<String> { /** * 反序列化时 若为 null 或 空字符串 * 皆反序列化 为 null * @param reader * @return * @throws IOException */ @Override public String read(JsonReader reader) throws IOException { if (reader.peek() == JsonToken.NULL) { reader.nextNull(); return null; } String res = reader.nextString(); return "".equals(res) ? null : res; } /** * 序列化时 若属性值 为null 则 序列化为 空字符串 * 反之 反序列化时 若属性值 为 null 或者为 空字符串时 -- * 则对应反序列化为 null * @param writer * @param value * @throws IOException */ @Override public void write(JsonWriter writer, String value) throws IOException { if (value == null) { writer.value(""); return; } writer.value(value); } }
创建适配器工厂
package sun.rain.amazing.gson.stringnull; import com.google.gson.Gson; import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapterFactory; import com.google.gson.reflect.TypeToken; /** * @author sunRainAmazing */ public class NullStringToEmptyAdapterFactory implements TypeAdapterFactory { @SuppressWarnings("unchecked") @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { Class<T> rawType = (Class<T>) type.getRawType(); if (rawType != String.class) { return null; } return (TypeAdapter<T>) new StringNullAdapter(); } }
测试类
@Data @AllArgsConstructor @NoArgsConstructor public class GsonStrNull { private String name; private String email; private Integer id; public GsonStrNull(String name, String email) { this.name = name; this.email = email; } public GsonStrNull(String name) { this.name = name; } public GsonStrNull(String name, Integer id) { this.name = name; this.id = id; } }
package sun.rain.amazing.gson.strnull; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.junit.Test; import sun.rain.amazing.gson.stringnull.GsonObjNull; import sun.rain.amazing.gson.stringnull.GsonStrNull; import sun.rain.amazing.gson.stringnull.NullStringToEmptyAdapterFactory; import sun.rain.amazing.gson.stringnull.NullToEmptyAdapterFactory; /** * @author sunRainAmazing */ public class GsonStringTypeAdapterFactoryTest { /** * {"name":"tom","email":"","id":12} * GsonStrNull(name=tom, email=null, id=12) */ @Test public void testNull(){ GsonStrNull g = new GsonStrNull("tom",12); Gson gson = new GsonBuilder() // 进行注册自定义的适配器工厂 .registerTypeAdapterFactory(new NullStringToEmptyAdapterFactory()) .create(); //序列化 String json = gson.toJson(g); System.out.println(json); //反序列化 g = gson.fromJson(json, GsonStrNull.class); System.out.println(g); } }
下面进一步封装
针对于String 、 Integer 、 Double 、Boolean类型
package sun.rain.amazing.gson.stringnull; import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import java.io.IOException; /** * 对于反序列化而言 这里 仅支持 * String * int / Integer * Double /double * Boolean / boolean * * * @author sunRainAmazing */ public class BaseNullAdapter<T> extends TypeAdapter<Object> { /** * 反序列化时 若为 null 或 空字符串 * 皆反序列化 为 null * @param reader * @return * @throws IOException */ @Override @SuppressWarnings("unchecked") public Object read(JsonReader reader) throws IOException { if (reader.peek() == JsonToken.NULL) { reader.nextNull(); return null; } // 这里仅针对与 Integer 和 Double类型 if (reader.peek() == JsonToken.NUMBER) { double res = reader.nextDouble(); if(Math.floor(res) == res){ return ((int) res); }else{ return res; } } if (reader.peek() == JsonToken.BOOLEAN) { return reader.nextBoolean(); } String res = reader.nextString(); return "".equals(res) ? null : res; } /** * 序列化时 若属性值 为null 则 序列化为 空字符串 * 反之 反序列化时 若属性值 为 null 或者为 空字符串时 -- * 则对应反序列化为 null * @param writer * @param value * @throws IOException */ @Override public void write(JsonWriter writer, Object value) throws IOException { if (value == null) { writer.value(""); return; } // 在 反序列化 是 无法动态 绑定其类型 if(value instanceof Number){ writer.value((Number) value); return; } if(value instanceof Boolean){ writer.value((Boolean) value); return; } writer.value(value.toString()); } }
package sun.rain.amazing.gson.stringnull; import com.google.gson.Gson; import com.google.gson.TypeAdapter; import com.google.gson.TypeAdapterFactory; import com.google.gson.reflect.TypeToken; /** * @author sunRainAmazing */ public class NullToEmptyAdapterFactory implements TypeAdapterFactory { @SuppressWarnings("unchecked") @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { Class<T> rawType = (Class<T>) type.getRawType(); if (!isRequiredType(rawType)) { return null; } return (TypeAdapter<T>) new BaseNullAdapter<T>(); } private boolean isRequiredType(Class cla){ return cla == int.class || cla == Integer.class || cla == String.class || cla == double.class || cla == Double.class || cla == boolean.class || cla == Boolean.class; } }
测试类
@Data @AllArgsConstructor @NoArgsConstructor public class GsonObjNull { private String name; private Integer integerType; private int in; private Double doubleType; private double dou; private Boolean boolType; private boolean bool; private Character ch; public GsonObjNull(String name, Character ch) { this.name = name; this.ch = ch; } }
package sun.rain.amazing.gson.strnull; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import org.junit.Test; import sun.rain.amazing.gson.stringnull.GsonObjNull; import sun.rain.amazing.gson.stringnull.NullToEmptyAdapterFactory; /** * @author sunRainAmazing */ public class GsonTypeAdapterFactoryTest { /** * {"name":"tom","integerType":12,"in":10, * "doubleType":12.36,"dou":15.32,"boolType":true,"bool":true,"ch":"A"} * * GsonObjNull(name=tom, integerType=12, in=10, * doubleType=12.36, dou=15.32, boolType=true, bool=true, ch=A) */ @Test public void testObjNull(){ GsonObjNull g = new GsonObjNull("tom",12,10, 12.36,15.32,true,true,'A'); Gson gson = new GsonBuilder() .registerTypeAdapterFactory(new NullToEmptyAdapterFactory()) .create(); //序列化 String json = gson.toJson(g); System.out.println(json); //反序列化 g = gson.fromJson(json, GsonObjNull.class); System.out.println(g); } /** * {"name":"tom","integerType":"","in":0,"doubleType":"","dou":0.0,"boolType":"","bool":false,"ch":"A"} * GsonObjNull(name=tom, integerType=null, in=0, doubleType=null, dou=0.0, boolType=null, bool=false, ch=A) */ @Test public void testObjNull1(){ GsonObjNull g = new GsonObjNull("tom",'A'); Gson gson = new GsonBuilder() .registerTypeAdapterFactory(new NullToEmptyAdapterFactory()) .create(); //序列化 String json = gson.toJson(g); System.out.println(json); //反序列化 g = gson.fromJson(json, GsonObjNull.class); System.out.println(g); } }
三种方式 各有优劣,
若无其他需求, 本人建议采用方式1