简介
new TypeToken<List<Person>>() {}.getType()
new TypeToken<List<Person>>() {}.getType()
compile 'com.google.code.gson:gson:2.8.1'
compile 'com.google.code.gson:gson:2.8.1'
使用时需要注意的一些细节
- 使用 Gson 反序列化时,只有当所有 JSON 串中的 key 和 JavaBean 中的定义的 field 的类型相匹配时才能成功解析,只要有一个 field 的类型不一致,就会造成解析失败。
class Person {
public String name;
public int age;
}
System.out.println(gson.fromJson("{'name':'包青天'}", Person.class).name);//包青天。引号既可以是单引号也可以是双引号
System.out.println(gson.fromJson("{\"name\":包青天}", Person.class).name);//包青天。任何类型的value都可以不带引号(包括String)
System.out.println(gson.fromJson("{'NAME':'包青天'}", Person.class).name);//null。严格区分大小写
System.out.println(gson.fromJson("{'age':0xff}", Person.class).age);//NumberFormatException。只能解析十进制数
System.out.println(gson.fromJson("{'age':true}", Person.class).age);//Expected an int but was BOOLEAN
System.out.println(gson.fromJson("{'age':1.23}", Person.class).age);//Expected an int but was 1.23
class Person {
public String name;
public int age;
}
System.out.println(gson.fromJson("{'name':'包青天'}", Person.class).name);//包青天。引号既可以是单引号也可以是双引号
System.out.println(gson.fromJson("{\"name\":包青天}", Person.class).name);//包青天。任何类型的value都可以不带引号(包括String)
System.out.println(gson.fromJson("{'NAME':'包青天'}", Person.class).name);//null。严格区分大小写
System.out.println(gson.fromJson("{'age':0xff}", Person.class).age);//NumberFormatException。只能解析十进制数
System.out.println(gson.fromJson("{'age':true}", Person.class).age);//Expected an int but was BOOLEAN
System.out.println(gson.fromJson("{'age':1.23}", Person.class).age);//Expected an int but was 1.23
-
使用Gson反序列化时,对JavaBean中的 field 的访问限制符是public还是private没任何要求,对构造方法也没任何要求
-
使用Gson反序列化时,在解析JSON数据前需要自己确定待解析的是JSON Object、JSON array、number、字符串……
-
JSON串中的false、true和JavaBean中的整型0、1之间不能相互转换
- JSON串中用不着的字段可以不在JavaBean中声明,JavaBean中可以声明JSON串中没有的字段
-
JSON串中的引号既可以是单引号也可以是双引号,且任何类型的value都可以不带引号(包括String)
- JSON串中的key只能是string类型的,而value可以是string、number、false/true、null、Object对象或者array数组
- JSON数组里的元素不要求是同一类型的,可以是任意json支持的类型
Google-gson 文档
Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object. Gson can work with arbitrary Java objects including pre-existing objects that you do not have source-code of.
Gson是一个可用于将Java对象转换为JSON表示形式的Java库。它也可以用于将JSON字符串转换为等效的Java对象。 Gson可以和任意Java对象一起使用,包括您没有源代码的预先存在的对象。
有几个开源项目可以将Java对象转换为JSON。但是,他们大多数都要求您将Java注解放在类中;如果您无法访问源代码,则无法执行此操作。大多数也不完全支持使用Java泛型。 Gson认为这两个都是非常重要的设计目标。
-
Provide simple toJson() and fromJson() methods to convert Java objects to JSON and vice-versa 提供简单的 toJson() 和 fromJson() 方法将Java对象转换为JSON,反之亦然
-
Allow pre-existing unmodifiable objects to be converted to and from JSON 允许将先前存在的不可修改对象转换为JSON或从JSON转换
-
Extensive support of Java Generics 广泛的支持Java泛型
-
Allow custom representations for objects 允许对象的自定义表示
-
For Maven check "Dependency Information" tab, on the left side.
-
Gson user guide : This guide contains examples on how to use Gson in your code. 本指南包含有关如何在代码中使用Gson的示例。
-
Gson design document : This document discusses issues we faced while designing Gson. It also include a comparison of Gson with other Java libraries that can be used for Json conversion 本文档讨论了我们在设计Gson时遇到的问题。它还包括将Gson与可用于Json转换的其他Java库进行比较
Gson使用时需要注意的混淆问题
-
问题:在不使用混淆工具进行apk打包时,一切正常;在使用混淆编译的方式进行apk打包后,就不能获取到JavaBean中的值了!
-
原因:使用Gson的fromJson方法反序列化时,要求 JavaBean 中的字段名必须与 json 串中的 key 完全一致,否则解析失败。而混淆后, JavaBean 的类名及其字段名称全部变成了A、B、C或a、b、c 等简称了,这与 json 串中的 key 不一致,进而导致解析失败。
-
解决:在使用混淆编译方式进行apk打包的时候,需要过滤掉所有相关的 JavaBean 。
#滤掉某个Java Bean 文件不进行混淆编译
-keep class com.lokinfo.m95xiu.bean.FamilyAssBean {*;}
#滤掉某个包下的所有.class文件不进行混淆编译
-keep class com.lokinfo.m95xiu.bean.** {*;}
#滤掉某个Java Bean 文件不进行混淆编译
-keep class com.lokinfo.m95xiu.bean.FamilyAssBean {*;}
#滤掉某个包下的所有.class文件不进行混淆编译
-keep class com.lokinfo.m95xiu.bean.** {*;}
GsonBuilder的API简介
-
Gson create() Creates a Gson instance based on the current configuration. 根据当前配置创建一个Gson实例。
-
addDeserializationExclusionStrategy(ExclusionStrategy strategy) Configures Gson to apply the passed in exclusion strategy during deserialization. 配置Gson在反序列化期间应用传递的排除策略。设置反序列化时字段采用策略ExclusionStrategy,如反序列化时不要某字段,当然可以采用@Expore代替。
- addSerializationExclusionStrategy(ExclusionStrategy strategy) Configures Gson to apply the passed in exclusion strategy during serialization. 同上
-
disableHtmlEscaping() By default, Gson escapes HTML characters such as < > etc. 默认情况下,Gson转义HTML字符,如<>等。禁止转义html标签
-
disableInnerClassSerialization() Configures Gson to exclude inner classes during serialization. 配置Gson在序列化期间排除内部类。
-
enableComplexMapKeySerialization() Enabling this feature will only change the serialized form if the map key is a complex type (i.e. 启用此功能将仅在映射密钥为复杂类型时更改序列化形式。
-
excludeFieldsWithModifiers(int... modifiers) Configures Gson to excludes all class fields that have the specified modifiers. 将Gson配置为排除具有指定修饰符的所有类字段。参数值由java.lang.reflect.Modifier提供。
-
excludeFieldsWithoutExposeAnnotation() Configures Gson to exclude all fields from consideration for serialization or deserialization that do not have the Expose annotation. 将Gson配置为将所有字段排除在不具有“公开”注释的序列化或反序列化中。设置没有@Expore则不序列化和反序列化。
-
generateNonExecutableJson() Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some special text. 通过使用一些特殊文本将生成的JSON前缀,使JSON中的输出JSON不可执行。在生成的Json串前多了【)]}'】这4个字符,且之后有一个换行
-
registerTypeAdapter(Type type, Object typeAdapter) Configures Gson for custom serialization or deserialization. 配置Gson以进行自定义序列化或反序列化。为某特定对象设置固定的序列和反序列方式,实现JsonSerializer和JsonDeserializer接口
-
registerTypeAdapterFactory(TypeAdapterFactory factory) Register a factory for type adapters. 为工厂注册类型适配器。
-
registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) Configures Gson for custom serialization or deserialization for an inheritance type hierarchy. 为继承类型层次结构的自定义序列化或反序列化配置Gson。
-
serializeNulls() Configure Gson to serialize null fields. 配置Gson序列化空字段。
- serializeSpecialFloatingPointValues() Section 2.4 of JSON specification disallows special double values (NaN, Infinity, -Infinity). JSON规范的第2.4节不允许特殊的双重值(NaN,Infinity,-Infinity)。
-
setDateFormat(String pattern) Configures Gson to serialize Date objects according to the pattern provided. 根据提供的样式,将Gson配置为序列化Date对象。设置日期时间格式,在序列化和反序化时均生效
- setDateFormat(int style) Configures Gson to to serialize Date objects according to the style value provided. 同上
- setDateFormat(int dateStyle, int timeStyle) Configures Gson to to serialize Date objects according to the style value provided. 同上
-
setExclusionStrategies(ExclusionStrategy... strategies) Configures Gson to apply a set of exclusion strategies during both serialization and deserialization. 配置Gson在序列化和反序列化期间应用一组排除策略。
-
setFieldNamingPolicy(FieldNamingPolicy namingConvention) Configures Gson to apply a specific naming policy to an object's field during serialization and deserialization. 配置Gson在序列化和反序列化期间,将特定的命名策略应用于对象的字段。值从枚举FieldNamingPolicy 中获取。
-
setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) Configures Gson to apply a specific naming policy strategy to an object's field during serialization and deserialization. 即:设置字段序列和反序列时名称显示,和@Serializer的作用一致。
-
setLenient() By default, Gson is strict and only accepts JSON as specified by RFC 4627. 默认情况下,Gson是严格的,只接受RFC 4627规定的JSON。
-
setLongSerializationPolicy(LongSerializationPolicy serializationPolicy) Configures Gson to apply a specific serialization policy for Long and long objects. 配置Gson为长对象应用特定的序列化策略。
-
setPrettyPrinting() Configures Gson to output Json that fits in a page for pretty printing. 配置Gson来输出适合漂亮打印的页面的Json。
-
setVersion(double ignoreVersionsAfter) Configures Gson to enable versioning support. 配置Gson以启用版本控制支持。是和@Since 和 @Until 一起使用的。
JsonElement 继承体系
public boolean isJsonObject() {
return this instanceof JsonObject;
}
x
public boolean isJsonObject() {
return this instanceof JsonObject;
}
public JsonObject getAsJsonObject() {
if (isJsonObject()) {
return (JsonObject) this;
}
throw new IllegalStateException("Not a JSON Object: " + this);
}
public JsonObject getAsJsonObject() {
if (isJsonObject()) {
return (JsonObject) this;
}
throw new IllegalStateException("Not a JSON Object: " + this);
}
private final LinkedTreeMap<String, JsonElement> members = new LinkedTreeMap();
private final LinkedTreeMap<String, JsonElement> members = new LinkedTreeMap();
public final class JsonArray extends JsonElement implements Iterable<JsonElement> //集合类都实现了此接口,所以JsonArray具有集合的功能
private final List<JsonElement> elements;
x
public final class JsonArray extends JsonElement implements Iterable<JsonElement> //集合类都实现了此接口,所以JsonArray具有集合的功能
private final List<JsonElement> elements;
public static final JsonNull INSTANCE = new JsonNull(); //单例
public static final JsonNull INSTANCE = new JsonNull(); //单例
JsonPrimitive 类
private static final Class<?>[] PRIMITIVE_TYPES = { Integer.TYPE, Long.TYPE, Short.TYPE, Float.TYPE, Double.TYPE, Byte.TYPE, Boolean.TYPE, Character.TYPE, Integer.class, Long.class, Short.class, Float.class, Double.class, Byte.class, Boolean.class, Character.class };
private static final Class<?>[] PRIMITIVE_TYPES = { Integer.TYPE, Long.TYPE, Short.TYPE, Float.TYPE, Double.TYPE, Byte.TYPE, Boolean.TYPE, Character.TYPE, Integer.class, Long.class, Short.class, Float.class, Double.class, Byte.class, Boolean.class, Character.class };
private Object value;
x
private Object value;
public boolean isString() {
return value instanceof String;
}
x
public boolean isString() {
return value instanceof String;
}
void setValue(Object primitive) {
if (primitive instanceof Character) {//对于Character类型的json元素需要特殊处理
// convert characters to strings since in JSON, characters are represented as a single character string
char c = ((Character) primitive).charValue();
this.value = String.valueOf(c);
} else {
//对于传入的其他json类型通过checkArgumeng进行过滤,如果不是是Number或者String和PRIMITIVE_TYPES里的一种的话,就会抛出异常。
$Gson$Preconditions.checkArgument(primitive instanceof Number || isPrimitiveOrString(primitive));
this.value = primitive;
}
}
x
void setValue(Object primitive) {
if (primitive instanceof Character) {//对于Character类型的json元素需要特殊处理
// convert characters to strings since in JSON, characters are represented as a single character string
char c = ((Character) primitive).charValue();
this.value = String.valueOf(c);
} else {
//对于传入的其他json类型通过checkArgumeng进行过滤,如果不是是Number或者String和PRIMITIVE_TYPES里的一种的话,就会抛出异常。
$Gson$Preconditions.checkArgument(primitive instanceof Number || isPrimitiveOrString(primitive));
this.value = primitive;
}
}
public String getAsString() {
if (isNumber())
return getAsNumber().toString();
if (isBoolean()) {
return getAsBooleanWrapper().toString();
}
return (String) value;
}
x
public String getAsString() {
if (isNumber())
return getAsNumber().toString();
if (isBoolean()) {
return getAsBooleanWrapper().toString();
}
return (String) value;
}
Gson、FastJson、Jackson性能对比
类库 | 样本数量 | 执行次数 | 最长时间(毫秒) | 最短时间(毫秒) | 平均时间(毫秒) |
---|---|---|---|---|---|
FastJson |
100000 | 10 | 2291.22 | 1416.70 | 1454.93 |
Jackson | 100000 | 10 | 1980.92 | 841.91 | 880.82 |
Gson | 100000 | 10 | 2383.02 | 1469.08 | 1520.38 |
【JSON反序列化 JSON => Object】
类库 | 样本数量 | 执行次数 | 最长时间(毫秒) | 最短时间(毫秒) | 平均时间(毫秒) |
---|---|---|---|---|---|
FastJson |
100000 | 10 | 7942.31 | 6340.55 | 6526.41 |
Jackson | 100000 | 10 | 7957.22 | 6623.85 | 6815.41 |
Gson | 100000 | 10 | 8235.15 | 7006.06 | 7364.75 |
【总结】
把Java对象JSON序列化,Jackson速度最快,在测试中比Gson快接近50%,FastJson和Gson速度接近。
把JSON反序列化成Java对象,FastJson、Jackson速度接近,Gson速度稍慢,不过差距很小。
示例代码
序列化与反序列化
public class Test {
public static Gson gson = new GsonBuilder().create();
public static void main(String[] args) {
objToJson();//普通对象
arrayToJson();//数组
listToJson();//集合
}
/**普通对象*/
public static void objToJson() {
String jsonString = gson.toJson(new Person("包青天", "广州"));
System.out.println("【JSON序列化 Object => JSON】" + jsonString);
Person person = gson.fromJson(jsonString, Person.class);//也可以用【new TypeToken<Person>() {}.getType()】
System.out.println("【JSON反序列化 JSON => Object】" + person);
}
/**数组*/
public static void arrayToJson() {
String jsonString = gson.toJson(new String[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" });
System.out.println("\n【JSON序列化 Array => JSON】" + jsonString);
String[] array = gson.fromJson(jsonString, String[].class);//也可以用【new TypeToken<String[]>() {}.getType()】
System.out.println("【JSON反序列化 JSON => Array】" + Arrays.toString(array));
//二维数组
String jsonString2 = gson.toJson(new int[][] { { 1, 2, 3 }, { 3, 4, 5 }, { 4, 5, 6 } });
System.out.println("\n【JSON序列化 Array => JSON】" + jsonString2);
int[][] array2 = gson.fromJson(jsonString2, int[][].class);
System.out.println("【JSON反序列化 JSON => Array】" + Arrays.toString(array2));
}
/**集合*/
public static void listToJson() {
//List
List<Person> persons = new ArrayList<Person>();
persons.add(new Person("包青天", "北京"));
persons.add(new Person("白乾涛", "上海"));
persons.add(new Person("bqt", "广州"));
String jsonString = gson.toJson(persons);
System.out.println("\n【JSON序列化 List => JSON】" + jsonString);
List<Person> persons2 = gson.fromJson(jsonString, new TypeToken<List<Person>>() {
}.getType());//支持带泛型
System.out.println("【JSON反序列化 JSON => List】" + persons2.toString());
//Map
Map<String, Integer> names = new HashMap<String, Integer>();
names.put("包青天", 1);
names.put("白乾涛", 2);
names.put("bqt", 3);
String jsonString2 = gson.toJson(names);
System.out.println("\n【JSON序列化 Map => JSON】" + jsonString2);
Map<String, Integer> names2 = gson.fromJson(jsonString2, new TypeToken<Map<String, Integer>>() {
}.getType());
System.out.println("【JSON反序列化 JSON => Map】" + names2.toString());
}
}
public class Test {
public static Gson gson = new GsonBuilder().create();
public static void main(String[] args) {
objToJson();//普通对象
arrayToJson();//数组
listToJson();//集合
}
/**普通对象*/
public static void objToJson() {
String jsonString = gson.toJson(new Person("包青天", "广州"));
System.out.println("【JSON序列化 Object => JSON】" + jsonString);
Person person = gson.fromJson(jsonString, Person.class);//也可以用【new TypeToken<Person>() {}.getType()】
System.out.println("【JSON反序列化 JSON => Object】" + person);
}
/**数组*/
public static void arrayToJson() {
String jsonString = gson.toJson(new String[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" });
System.out.println("\n【JSON序列化 Array => JSON】" + jsonString);
String[] array = gson.fromJson(jsonString, String[].class);//也可以用【new TypeToken<String[]>() {}.getType()】
System.out.println("【JSON反序列化 JSON => Array】" + Arrays.toString(array));
//二维数组
String jsonString2 = gson.toJson(new int[][] { { 1, 2, 3 }, { 3, 4, 5 }, { 4, 5, 6 } });
System.out.println("\n【JSON序列化 Array => JSON】" + jsonString2);
int[][] array2 = gson.fromJson(jsonString2, int[][].class);
System.out.println("【JSON反序列化 JSON => Array】" + Arrays.toString(array2));
}
/**集合*/
public static void listToJson() {
//List
List<Person> persons = new ArrayList<Person>();
persons.add(new Person("包青天", "北京"));
persons.add(new Person("白乾涛", "上海"));
persons.add(new Person("bqt", "广州"));
String jsonString = gson.toJson(persons);
System.out.println("\n【JSON序列化 List => JSON】" + jsonString);
List<Person> persons2 = gson.fromJson(jsonString, new TypeToken<List<Person>>() {
}.getType());//支持带泛型
System.out.println("【JSON反序列化 JSON => List】" + persons2.toString());
//Map
Map<String, Integer> names = new HashMap<String, Integer>();
names.put("包青天", 1);
names.put("白乾涛", 2);
names.put("bqt", 3);
String jsonString2 = gson.toJson(names);
System.out.println("\n【JSON序列化 Map => JSON】" + jsonString2);
Map<String, Integer> names2 = gson.fromJson(jsonString2, new TypeToken<Map<String, Integer>>() {
}.getType());
System.out.println("【JSON反序列化 JSON => Map】" + names2.toString());
}
}
直接解析Json串
String json = "{'flag':true,'data':{'name':'张三','age':18,'address':'广州'}}";
JsonElement element = new JsonParser().parse(json);// 获得根节点元素
JsonObject root = element.getAsJsonObject();//必须事先知道根节点是 JsonObject还是JsonArray ,框架本身没法帮你决定
JsonPrimitive flagElement = root.getAsJsonPrimitive("flag");//取得根节点下的某个节点的值
boolean flag = flagElement.getAsBoolean();
System.out.println("\n【解析Json串】" + flag);
JsonObject dataJson = root.getAsJsonObject("data");//逐层向内解析
Person person = gson.fromJson(dataJson, Person.class);
System.out.println("【JSON反序列化】" + person);
String json = "{'flag':true,'data':{'name':'张三','age':18,'address':'广州'}}";
JsonElement element = new JsonParser().parse(json);// 获得根节点元素
JsonObject root = element.getAsJsonObject();//必须事先知道根节点是 JsonObject还是JsonArray ,框架本身没法帮你决定
JsonPrimitive flagElement = root.getAsJsonPrimitive("flag");//取得根节点下的某个节点的值
boolean flag = flagElement.getAsBoolean();
System.out.println("\n【解析Json串】" + flag);
JsonObject dataJson = root.getAsJsonObject("data");//逐层向内解析
Person person = gson.fromJson(dataJson, Person.class);
System.out.println("【JSON反序列化】" + person);
Bean
class Person {
public String name;//对字段的访问限制符public还是private没任何限制,但字段名必须和Json串中的完全一致
public String address;
public Person(String name, String address) {//对构造方法也没任何限制
this.name = name;
this.address = address;
}
@Override
public String toString() {
return "name=" + name + " & " + "address=" + address;
}
}
class Person {
public String name;//对字段的访问限制符public还是private没任何限制,但字段名必须和Json串中的完全一致
public String address;
public Person(String name, String address) {//对构造方法也没任何限制
this.name = name;
this.address = address;
}
public String toString() {
return "name=" + name + " & " + "address=" + address;
}
}
2017-9-12