目前比较流行的处理json数据的工具是Jackson和Fastjson,只有少数的公司使用Gson(一些公司对外部插件的安全性要求问题,如某些银行),这里对Gson的使用作个记录。
1、引进Gson jar包
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
2、Gson工具类
Q: 直接Gson gson = new Gson; 也是可以使用的,那为什么要自己写Gson工具类呢?
A: 写工具类是为了统一处理一些特殊情况,如null值的处理等。
import java.io.IOException;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
public final class GsonUtils {
private static String DATE_TIME_PATTERN_DEFAULT = "yyyy-MM-dd HH:mm:ss";
private static ThreadLocal<DateFormat> dateFormat = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat(DATE_TIME_PATTERN_DEFAULT);
}
};
private static TypeAdapter<BigDecimal> decimalTypeAdapter = new TypeAdapter<BigDecimal>() {
@Override
public BigDecimal read(JsonReader in) throws IOException {
try {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return BigDecimal.ZERO;
}
return BigDecimal.valueOf(in.nextDouble());
} catch (NumberFormatException e) {
return BigDecimal.ZERO;
}
}
@Override
public void write(JsonWriter out, BigDecimal value) throws IOException {
out.value(value);
}
};
private static TypeAdapter<BigInteger> bigIntegerTypeAdapter = new TypeAdapter<BigInteger>() {
@Override
public BigInteger read(JsonReader in) throws IOException {
try {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return BigInteger.ZERO;
}
return BigInteger.valueOf(in.nextLong());
} catch (NumberFormatException e) {
return BigInteger.ZERO;
}
}
@Override
public void write(JsonWriter out, BigInteger value) throws IOException {
out.value(value);
}
};
private static TypeAdapter<Double> doubleTypeAdapter = new TypeAdapter<Double>() {
@Override
public Double read(JsonReader in) throws IOException {
try {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return 0d;
}
return in.nextDouble();
} catch (NumberFormatException e) {
return 0d;
}
}
@Override
public void write(JsonWriter out, Double value) throws IOException {
out.value(value);
}
};
private static TypeAdapter<Float> floatTypeAdapter = new TypeAdapter<Float>() {
@Override
public Float read(JsonReader in) throws IOException {
try {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return 0f;
}
return Float.parseFloat(String.valueOf(in.nextDouble()));
} catch (NumberFormatException e) {
return 0f;
}
}
@Override
public void write(JsonWriter out, Float value) throws IOException {
out.value(value);
}
};
private static TypeAdapter<Long> longTypeAdapter = new TypeAdapter<Long>() {
@Override
public Long read(JsonReader in) throws IOException {
try {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return 0L;
}
return in.nextLong();
} catch (NumberFormatException e) {
return 0L;
}
}
@Override
public void write(JsonWriter out, Long value) throws IOException {
out.value(value);
}
};
private static TypeAdapter<Integer> integerTypeAdapter = new TypeAdapter<Integer>() {
@Override
public Integer read(JsonReader in) throws IOException {
try {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return 0;
}
return in.nextInt();
} catch (NumberFormatException e) {
return 0;
}
}
@Override
public void write(JsonWriter out, Integer value) throws IOException {
out.value(value);
}
};
private static TypeAdapter<Boolean> booleanTypeAdapter = new TypeAdapter<Boolean>() {
@Override
public Boolean read(JsonReader in) throws IOException {
try {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return Boolean.FALSE;
}
return in.nextBoolean();
} catch (IllegalArgumentException e) {
return Boolean.FALSE;
}
}
@Override
public void write(JsonWriter out, Boolean value) throws IOException {
out.value(value);
}
};
private static TypeAdapter<Date> dateTypeAdapter = new TypeAdapter<Date>() {
@Override
public Date read(JsonReader in) throws IOException {
try {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return dateFormat.get().parse(in.nextString());
} catch (IllegalArgumentException | ParseException e) {
return null;
}
}
@Override
public void write(JsonWriter out, Date value) throws IOException {
out.value(dateFormat.get().format(value));
}
};
static class StringNullAdapter extends TypeAdapter<String> {
@Override
public String read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return "";
}
return reader.nextString();
}
@Override
public void write(JsonWriter writer, String value) throws IOException {
if (value == null) {
writer.nullValue();
return;
}
writer.value(value);
}
}
static class NullStringToEmptyAdapterFactory<T> implements TypeAdapterFactory {
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();
}
}
private static Gson gson;
private GsonUtils() {
gson = GsonSingleton.GsonFactory.getGson();
}
private enum GsonSingleton {
GsonFactory;
private Gson gsonInner;
private GsonSingleton() {
gsonInner = new GsonBuilder().registerTypeAdapter(Integer.class, integerTypeAdapter).registerTypeAdapter(Long.class,
longTypeAdapter).registerTypeAdapter(Float.class, floatTypeAdapter).registerTypeAdapter(Double.class,
doubleTypeAdapter).registerTypeAdapter(Boolean.class, booleanTypeAdapter).registerTypeAdapter(BigInteger.class,
bigIntegerTypeAdapter).registerTypeAdapter(BigDecimal.class, decimalTypeAdapter).registerTypeAdapter(Date.class,
dateTypeAdapter).registerTypeAdapterFactory(new NullStringToEmptyAdapterFactory<String>()).setLenient().serializeNulls()
//.setDateFormat(DATE_TIME_PATTERN_DEFAULT)
.create();
}
public Gson getGson() {
return gsonInner;
}
}
public static JsonElement toJsonElement(Object obj) {
return GsonSingleton.GsonFactory.getGson().toJsonTree(obj);
}
public static String toJsonStr(Object obj) {
return gson.toJson(obj);
}
public static <T> T fromJson(String json, Class<T> classOfT) {
return gson.fromJson(json, classOfT);
}
public static <T> T fromJson(String json, Type type) {
return gson.fromJson(json, type);
}
}
3、常用注解
@SerializedName("user_name") //能指定该字段在JSON中对应的字段名称
@SerializedName(value = "name", alternate = {"name1","name2"})
@Expose //指定该字段是否能够序列化或者反序列化,默认的是都支持(true)
@Expose(serialize = false, deserialize = false)
@Since(1.0)代表从版本1.0之后才生效
@Until(0.9)代表着在0.9版本之前都是生效的
-——————————————————-
创建测试数据model
{
"id": 1,
"user_name": "zhangsan",
"password": "123456qwe",
"age": 12,
"student": true,
"balance1": 1.123,
"balance2": 1.123,
"balance": 1.456,
"createTime": "2020-04-07T06:20:52.497+0000",
"descr": "说明内容……",
"sub": {
"id": null,
"user_name": "zhangsan",
"password": "",
"age": null,
"student": null,
"balance1": null,
"balance2": null,
"balance": null,
"createTime": null,
"descr": null
},
"subList": [
{
"id": 2,
"user_name": "zhangsan",
"password": "123456qwe",
"age": 12,
"student": true,
"balance1": 1.123,
"balance2": 1.123,
"balance": 1.123,
"createTime": "2020-04-07T06:20:52.497+0000",
"descr": "说明内容……"
},
{
"id": 3,
"user_name": "zhangsan",
"password": "123456qwe",
"age": 12,
"student": false,
"balance1": 1.123,
"balance2": 1.123,
"balance": 1.456,
"createTime": "2020-04-07T06:20:52.497+0000",
"descr": ""
}
]
}
测试结果