去fastjson笔记
fastjson近些年频频爆出安全漏洞,现在已经是互联网的过街老鼠了,建议早去早好,网上搜索了下,相对而言google出品的gson目前还没听说有重大安全问题。下面是gson替换fastjson可能会遇到的一些坑。
一、美化输出格式
new GsonBuilder().setPrettyPrinting().create();
二、自定义date的输出格式
new GsonBuilder()
.setPrettyPrinting() //美化输出格式
.setDateFormat("yyyy-MM-dd HH:mm:ss.SSS") //设置date字段的输出格式
.create();
写一段单元测试代码:
package test.nio.study;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;
import java.util.*;
public class GsonTest {
public Gson gson() {
return new GsonBuilder()
.setPrettyPrinting() //美化输出格式
.setDateFormat("yyyy-MM-dd HH:mm:ss.SSS") //设置date字段的输出格式
.create();
}
@Data
@NoArgsConstructor
public class InnerTestClass {
private Integer intField;
private Long longField;
private String strField;
private Date dateField;
private List<InnerTestClass> listField;
private Map<String, String> mapField;
}
@Test
public void testGson() {
InnerTestClass test = new InnerTestClass();
test.intField = 1;
test.longField = 2L;
test.dateField = new Date();
test.mapField = new HashMap<>();
test.mapField.put("test", "hello world");
test.listField = new ArrayList<>();
InnerTestClass test2 = new InnerTestClass();
test2.dateField = new Date();
test.listField.add(test2);
System.out.println(gson().toJson(test));
}
}
输出如下:
{
"intField": 1,
"longField": 2,
"dateField": "2020-06-14 23:04:17.202",
"listField": [
{
"dateField": "2020-06-14 23:04:17.202"
}
],
"mapField": {
"test": "hello world"
}
}
三、兼容多种date字符串/timestamp的反序列化
{
"dateField": "2020-06-14 23:04:17",
"listField": [
{
"dateField": "2020-06-14 23:04:17.202"
},
{
"dateField": 1592148201102
},
{
"dateField": ""
}
]
}
如果上面这段json,尝试用刚才生成的gson实例反序列化的话,会报错Invalid time zone indicator ' ',原因是 第1个dateField没有带.SSS的毫秒部分,第3个dateField是一个timestamp的long型数字,更无法匹配yyyy-MM-dd HH:mm:ss.SSS,第4个是空字符串,仍然无法匹配。
可以参考下面这样:
public Gson gson() {
String dateFormatWithMS = "yyyy-MM-dd HH:mm:ss.SSS";
String dateFormatNoMS = "yyyy-MM-dd HH:mm:ss";
GsonBuilder builder = new GsonBuilder();
builder.registerTypeAdapter(Date.class, (JsonDeserializer<Date>) (json, typeOfT, context) -> {
if (json == null || json.toString().equalsIgnoreCase("\"\"")) {
//空字符判断
return null;
}
JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive();
SimpleDateFormat sdfMS = new SimpleDateFormat(dateFormatWithMS);
SimpleDateFormat sdfNoMS = new SimpleDateFormat(dateFormatNoMS);
Date dt = null;
try {
if (jsonPrimitive.isString()) {
if (jsonPrimitive.getAsString().length() == 19) {
//这里只是示例,简单用长度来判断是哪种格式
//yyyy-MM-dd HH:mm:ss格式
dt = sdfNoMS.parse(json.getAsString());
} else {
//yyyy-MM-dd HH:mm:ss.SSS格式
dt = sdfMS.parse(json.getAsString());
}
} else if (jsonPrimitive.isNumber()) { //兼容timestamp类型
dt = new Date(jsonPrimitive.getAsLong());
}
} catch (Exception e) {
//错误日志记录,略
e.printStackTrace();
}
return dt;
});
Gson gson = builder
.setDateFormat(dateFormatWithMS)
.setPrettyPrinting()
.create();
return gson;
}
这样,刚才这4种情况的date解析都能兼容了。
四、字段别名
@SerializedName(value = "int_field", alternate = {"aaa", "bbb"})
private Integer intField;
这样的话,json字符串中的int_field, aaa, bbb这3种名字,都能映射到intField上。
五、数组解析
@Test
public void testParseList() {
String json = "[\"A\",\"B\",\"C\"]";
List<String> list1 = gson().fromJson(json, new TypeToken<List<String>>() {
}.getType());
System.out.println(list1.size());
}
TypeToken是个很有用的东西,建议大家多研究。
注:关于Calendar类型的定制,可参考我的另一篇文章 Gson如何自定义Calendar序列化/反序列化
作者:菩提树下的杨过
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
浙公网安备 33010602011771号