那么,来看下空对象反序列化会不会出现异常:
String jsonObjectEmptyCase = "{}"; // fastjson JSONObject jsonObjectEmpty = JSON.parseObject(jsonObjectEmptyCase); System.out.println(jsonObjectEmpty); System.out.println(jsonObjectEmpty.size()); // 输出: // {} // 0 // Gson JsonObject jsonObjectGsonEmpty = gson.fromJson(jsonObjectEmptyCase, JsonObject.class); System.out.println(jsonObjectGsonEmpty); System.out.println(jsonObjectGsonEmpty.size()); // 输出: // {} // 0没有异常,开心。
看看空数组呢,毕竟[]感觉比{}更加容易出错。
String jsonArrayEmptyCase = "[]"; // fastjson JSONArray jsonArrayEmpty = JSON.parseArray(jsonArrayEmptyCase); System.out.println(jsonArrayEmpty); System.out.println(jsonArrayEmpty.size()); // 输出: // [] // 0 // Gson JsonArray jsonArrayGsonEmpty = gson.fromJson(jsonArrayEmptyCase, JsonArray.class); System.out.println(jsonArrayGsonEmpty); System.out.println(jsonArrayGsonEmpty.size()); // 输出: // [] // 0两个框架也都没有问题,完美解析。
范型处理解析泛型是一个非常常用的功能,我们项目中大部分fastjson代码就是在解析json和Java Bean。
// 实体类 User user = new User(); user.setId(1L); user.setUserName("马云"); // fastjson List<User> userListResultFastjson = JSONArray.parseArray(JSON.toJSONString(userList), User.class); List<User> userListResultFastjson2 = JSON.parseObject(JSON.toJSONString(userList), new TypeReference<List<User>>(){}); System.out.println(userListResultFastjson); System.out.println("userListResultFastjson2" + userListResultFastjson2); // 输出: // userListResultFastjson[User [Hash = 483422889, id=1, userName=马云], null] // userListResultFastjson2[User [Hash = 488970385, id=1, userName=马云], null] // Gson List<User> userListResultTrue = gson.fromJson(gson.toJson(userList), new TypeToken<List<User>>(){}.getType()); System.out.println("userListResultGson" + userListResultGson); // 输出: // userListResultGson[User [Hash = 1435804085, id=1, userName=马云], null]可以看出,Gson也能支持泛型。
List/Map写入这一点fastjson和Gson有区别,Gson不支持直接将List写入value,而fastjson支持。
所以Gson只能将List解析后,写入value中,详见如下代码:
// 实体类 User user = new User(); user.setId(1L); user.setUserName("马云"); // fastjson JSONObject jsonObject1 = new JSONObject(); jsonObject1.put("user", user); jsonObject1.put("userList", userList); System.out.println(jsonObject1); // 输出: // {"userList":[{"id":1,"userName":"马云"},null],"user":{"id":1,"userName":"马云"}} // Gson JsonObject jsonObject = new JsonObject(); jsonObject.add("user", gson.toJsonTree(user)); System.out.println(jsonObject); // 输出: // {"user":{"id":1,"userName":"马云"},"userList":[{"id":1,"userName":"马云"},null]}如此一来,Gson看起来就没有fastjson方便,因为放入List是以gson.toJsonTree(user)的形式放入的。这样就不能先入对象,在后面修改该对象了。(有些同学比较习惯先放入对象,再修改对象,这样的代码就得改动)
驼峰与下划线转换驼峰转换下划线依靠的是修改Gson的序列化模式,修改为LOWER_CASE_WITH_UNDERSCORES
GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES); Gson gsonUnderScore = gsonBuilder.create(); System.out.println(gsonUnderScore.toJson(user)); // 输出: // {"id":1,"user_name":"马云"} 常见问题排雷下面整理了我们在公司项目迁移Gson过程中,踩过的坑,这些坑现在写起来感觉没什么技术含量。但是这才是我写这篇文章的初衷,帮助大家把这些很难发现的坑避开。
这些问题有的是在测试进行回归测试的时候发现的,有的是在自测的时候发现的,有的是在上线后发现的,比如Swagger挂了这种不会去测到的问题。
Date序列化方式不同不知道大家想过一个问题没有,如果你的项目里有缓存系统,使用fastjson写入的缓存,在你切换Gson后,需要用Gson解析出来。所以就一定要保证两个框架解析逻辑是相同的,但是,显然这个愿望是美好的。
在测试过程中,发现了Date类型,在两个框架里解析是不同的方式。
fastjson:Date直接解析为Unix
Gson:直接序列化为标准格式Date
导致了Gson在反序列化这个json的时候,直接报错,无法转换为Date。
解决方案:
新建一个专门用于解析Date类型的类:
import com.google.gson.TypeAdapter; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.util.Date; public class MyDateTypeAdapter extends TypeAdapter<Date> { @Override public void write(JsonWriter out, Date value) throws IOException { if (value == null) { out.nullValue(); } else { out.value(value.getTime()); } } @Override public Date read(JsonReader in) throws IOException { if (in != null) { return new Date(in.nextLong()); } else { return null; } } }接着,在创建Gson时,把他放入作为Date的专用处理类:
Gson gson = new GsonBuilder().registerTypeAdapter(Date.class,new MyDateTypeAdapter()).create();这样就可以让Gson将Date处理为Unix。
当然,这只是为了兼容老的缓存,如果你觉得你的仓库没有这方面的顾虑,可以忽略这个问题。
SpringBoot异常切换到Gson后,使用SpringBoot搭建的Web项目的接口直接请求不了了。报错类似:
org.springframework.http.converter.HttpMessageNotWritableException因为SpringBoot默认的Mapper是Jackson解析,我们切换为了Gson作为返回对象后,Jackson解析不了了。
解决方案:
application.properties里面添加:
#Preferred JSON mapper to use for HTTP message conversion spring.mvc.converters.preferred-json-mapper=gson Swagger异常这个问题和上面的SpringBoot异常类似,是因为在SpringBoot中引入了Gson,导致 swagger 无法解析 json。
采用类似下文的解决方案(添加Gson适配器):
引入swagger/