用法详解参考文章,点击这里
1. 创建GSON的两种方法
使用Gson的第一步是创建一个Gson对象,创建爱你Gson对象有两种方式:
- 使用 new Gson()
- 创建GsonBuilder实例,使用 create() 方法
使用new Gson(),此时会创建一个带有默认配置选项的Gson实例,如果不想使用默认配置,那么就可以使用GsonBuilder。
//serializeNulls()是GsonBuilder提供的一种配置,当字段值为空或null时,依然对该字段进行转换
Gson gson = new GsonBuilder().serializeNulls().create();
使用GsonBuilder创建Gson实例的步骤:
首先创建GsonBuilder,然后调用GsonBuilder提供的各种配置方法进行配置,
最后调用GsonBuilder的create方法,将基于当前的配置创建一个Gson实例。
GsonBuilder的一些配置
参考文章,点击这里
详情配置,点击这里
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation() //不对没有用@Expose注解的属性进行操作
.enableComplexMapKeySerialization() //当Map的key为复杂对象时,需要开启该方法
.serializeNulls() //当字段值为空或null时,依然对该字段进行转换
.setDateFormat("yyyy-MM-dd HH:mm:ss:SSS") //时间转化为特定格式
.setPrettyPrinting() //对结果进行格式化,增加换行
.disableHtmlEscaping() //防止特殊字符出现乱码
.registerTypeAdapter(User.class,new UserAdapter()) //为某特定对象设置固定的序列或反序列方式,自定义Adapter需实现JsonSerializer或者JsonDeserializer接口
.create();
getAsString()方法返回JsonNull异常问题解决
概述
在使用google.gson工具时,JsonElement的getAsString()方法返回JsonNull异常问题。
问题描述
使用google.gson工具时经常会使用的就是反序列化功能。比如看下面的一个方法:
private static JsonParser parser= new JsonParser();
public String parseJsonString(String raw) {
JsonElement jsonElement = JSON_PARSER.parse(raw);
JsonObject jsonObject = jsonElement.getAsJsonObject();
JsonElement dataType = jsonObject.has("dataType")? jsonObject.get("dataType"): null;
if(dataType != null) {
return jsonObject.get("dataType").getAsString();
}
return "null";
}
上述代码执行到if语句处会判定dataType != null,实际上这个判断根本就无法过滤json为null的情况,比如有如下的json数据:
{
"dataType": null
}
下述代码返回的结果为:
JsonElement dataType = jsonObject.has("dataType")? jsonObject.get("dataType"): null;
//因为json数据中有"dataType"键,所以jsonObject.has("dataType")会返回true,那么dataType的值就是jsonObject.get("dataType")的值,也就是上述json数据中的所谓的null
dataType实际上并不是所谓的java中的null,而是一种json所表征的null,它既不是字符串,同时dataType!=null会判为true,因为dataType中是存有数据的,它存的是一种表征json值为null的数据,因为dataType!=null会判为true,然后会进入if条件语句块执行getAsString(),那么此时会报JsonNull的异常。所以上述的判断语句不能只用dataType != null来做判断条件,还需要加一条专门用来判断json为null的语句,即:isJsonNull()方法,这是JsonElement类的非静态方法。所以下述条件判断才是正确的:
if(dataType != null && !dataType.isJsonNull()) {
return jsonObject.get("dataType").getAsString();
}
//这一次则无法进入if语句块内部,因为:
dataType.isJsonNull()返回true,则
!dataType.isJsonNull()返回false
自定义的返回:setExclusionStrategies
class Item {
String name;
@Expose
public int age;
public void gson() {
// 过滤掉声明为 protcted 的变量
Gson gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes f) {
//过滤掉字段名包含"age"
return f.getName().contains("age");
}
@Override
public boolean shouldSkipClass(Class<?> clazz) {
//过滤掉 类名包含 Bean的类
return clazz.getName().contains("Bean");
}
}).create();
}
}
公司项目中使用的实例:
如果你 Java 对象中包含一个正常的 Floats 或者 Doubles 类型的数据,是可以正常序列化得到 JSON的,如果你传入 Float.POSITIVE_INFINITY 值,Gson 将会抛出异常,因为这个值是不能符合 JSON 标准的
解决的办法就是通过 GsonBuilder 设置 serializeSpecialFloatingPointValues() 方法
参考文章,点击这里
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation() //不对没有用@Expose注解的属性进行操作
.enableComplexMapKeySerialization() //当Map的key为复杂对象时,需要开启该方法
.serializeNulls() //当字段值为空或null时,依然对该字段进行转换
.setDateFormat("yyyy-MM-dd HH:mm:ss:SSS") //时间转化为特定格式
.setPrettyPrinting() //对结果进行格式化,增加换行
.disableHtmlEscaping() //防止特殊字符出现乱码
.registerTypeAdapter(User.class,new UserAdapter()) //为某特定对象设置固定的序列或反序列方式,自定义Adapter需实现JsonSerializer或者JsonDeserializer接口
.create();
/*
* Copyright (c) 2020. XiaoMi Inc. All Rights Reserved.
* Authors: Sun Zhenkai <sunzhenkai@xiaomi.com>.
* Created on 2020/3/13 14:54:39.
*/
import org.apache.thrift.TSerializer;
import org.apache.thrift.protocol.TSimpleJSONProtocol;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Type;
public class GsonUtils {
private static final Logger logger = LoggerFactory.getLogger(GsonUtils.class);
static GsonBuilder gsonBuilder = new GsonBuilder();
private static final Gson gson = new Gson();
public static final Gson gsoner = gsonBuilder
.registerTypeAdapter(Double.class, new DoubleAdapter())
.registerTypeAdapter(Float.class, new FloatAdapter())
.setExclusionStrategies(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
return fieldAttributes.getName().equals("__isset_bit_vector");
}
@Override
public boolean shouldSkipClass(Class<?> aClass) {
return false;
}
}
).create();
private static class DoubleAdapter implements JsonSerializer<Double> {
@Override
public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) {
if (src == null || Double.isNaN(src) || Double.isInfinite(src)) {
logger.warn("illegal double value [{}], use 0 instead", src);
return gson.toJsonTree(0);
} else {
return gson.toJsonTree(src);
}
}
}
private static class FloatAdapter implements JsonSerializer<Float> {
@Override
public JsonElement serialize(Float src, Type typeOfSrc, JsonSerializationContext context) {
if (src == null || Float.isNaN(src) || Float.isInfinite(src)) {
logger.warn("illegal float value [{}], use 0 instead", src);
return gson.toJsonTree(0);
} else {
return gson.toJsonTree(src);
}
}
}
}