在使用gson过程中,一般会将数据存在一个对象模型中,使用gson将模型转换成json字符串用于数据交互。

代码形如:

  1. ArrayList<String> list = new ArrayList<>();
  2. list.add("test1");
  3. list.add("test2");
  4. Gson gson = new Gson();
  5. System.out.println("list to json is : "+gson.toJson(list));

程序输出内容为:

  1. list to json is : ["test1","test2"]

但是当转化对象是匿名类时:

  1. ArrayList<String> arrayList = new ArrayList<String>() {{
  2. add("对");
  3. add("不对");
  4. }};
  5. Gson gson = new Gson();
  6. System.out.println("isAnonymousClass list to json is : "+gson.toJson(arrayList));

程序输出内容为:

  1. isAnonymousClass list to json is : null

同理,如果使用模型对象,模型的某个字段的实例对象为匿名类,这个字段序列化的结果也是null。

这里我们研究一下gson的实现来分析原因:

首先,通过gson.toJson方法的实现很容易招到com.google.gson.Gson#toJson(java.lang.Object, java.lang.reflect.Type, com.google.gson.stream.JsonWriter) 这个方法,实现如下:

  1. /**
  2. * Writes the JSON representation of {@code src} of type {@code typeOfSrc} to
  3. * {@code writer}.
  4. * @throws JsonIOException if there was a problem writing to the writer
  5. */
  6. @SuppressWarnings("unchecked")
  7. public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
  8. TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc));
  9. boolean oldLenient = writer.isLenient();
  10. writer.setLenient(true);
  11. boolean oldHtmlSafe = writer.isHtmlSafe();
  12. writer.setHtmlSafe(htmlSafe);
  13. boolean oldSerializeNulls = writer.getSerializeNulls();
  14. writer.setSerializeNulls(serializeNulls);
  15. try {
  16. ((TypeAdapter<Object>) adapter).write(writer, src);
  17. } catch (IOException e) {
  18. throw new JsonIOException(e);
  19. } finally {
  20. writer.setLenient(oldLenient);
  21. writer.setHtmlSafe(oldHtmlSafe);
  22. writer.setSerializeNulls(oldSerializeNulls);
  23. }
  24. }

进入getAdapter方法

  1. public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
  2. TypeAdapter<?> cached = typeTokenCache.get(type);
  3. if (cached != null) {
  4. return (TypeAdapter<T>) cached;
  5. }
  6.  
  7. Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
  8. boolean requiresThreadLocalCleanup = false;
  9. if (threadCalls == null) {
  10. threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
  11. calls.set(threadCalls);
  12. requiresThreadLocalCleanup = true;
  13. }
  14.  
  15. // the key and value type parameters always agree
  16. FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
  17. if (ongoingCall != null) {
  18. return ongoingCall;
  19. }
  20.  
  21. try {
  22. FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
  23. threadCalls.put(type, call);
  24.  
  25. for (TypeAdapterFactory factory : factories) {
  26. TypeAdapter<T> candidate = factory.create(this, type);
  27. if (candidate != null) {
  28. call.setDelegate(candidate);
  29. typeTokenCache.put(type, candidate);
  30. return candidate;
  31. }
  32. }
  33. throw new IllegalArgumentException("GSON cannot handle " + type);
  34. } finally {
  35. threadCalls.remove(type);
  36.  
  37. if (requiresThreadLocalCleanup) {
  38. calls.remove();
  39. }
  40. }
  41. }
  1.  

这里,获取adapter时,会从默认的工厂列表中逐个获取工厂,基于传入的类型获取adapter实例,

这里我们关注的是com.google.gson.internal.Excluder这个工厂,

  1. public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
  2. Class<?> rawType = type.getRawType();
  3. final boolean skipSerialize = excludeClass(rawType, true);
  4. final boolean skipDeserialize = excludeClass(rawType, false);
  5.  
  6. if (!skipSerialize && !skipDeserialize) {
  7. return null;
  8. }
  9.  
  10. return new TypeAdapter<T>() {
  11. /** The delegate is lazily created because it may not be needed, and creating it may fail. */
  12. private TypeAdapter<T> delegate;
  13.  
  14. @Override public T read(JsonReader in) throws IOException {
  15. if (skipDeserialize) {
  16. in.skipValue();
  17. return null;
  18. }
  19. return delegate().read(in);
  20. }
  21.  
  22. @Override public void write(JsonWriter out, T value) throws IOException {
  23. if (skipSerialize) {
  24. out.nullValue();
  25. return;
  26. }
  27. delegate().write(out, value);
  28. }
  29.  
  30. private TypeAdapter<T> delegate() {
  31. TypeAdapter<T> d = delegate;
  32. return d != null
  33. ? d
  34. : (delegate = gson.getDelegateAdapter(Excluder.this, type));
  35. }
  36. };
  37. }

这里

  1. public boolean excludeClass(Class<?> clazz, boolean serialize) {
  2. if (version != Excluder.IGNORE_VERSIONS
  3. && !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class))) {
  4. return true;
  5. }
  6.  
  7. if (!serializeInnerClasses && isInnerClass(clazz)) {
  8. return true;
  9. }
  10.  
  11. if (isAnonymousOrLocal(clazz)) {
  12. return true;
  13. }
  14.  
  15. List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies;
  16. for (ExclusionStrategy exclusionStrategy : list) {
  17. if (exclusionStrategy.shouldSkipClass(clazz)) {
  18. return true;
  19. }
  20. }
  21.  
  22. return false;
  23. }

这里调用了isAnonymousOrLocal这个方法(从方法名称来看就是判断是否是匿名类或本地类,其判断是否是匿名类的逻辑是使用的java.lang.Class#isAnonymousClass方法,根据类名判断),由于skipSerialize和skipDeserialize 都由这个逻辑返回了true,最后create方法返回了Excluder工厂生成adapter对象.

由Excluder的注释和返回的TypeAdapter对象都很容易看出,它的作用就是忽略该对象的j转换,最终返回null

关于Gson无法将匿名类转化为json字符串的问题的更多相关文章

  1. 使用DataContractJsonSerializer类将类型实例序列化为JSON字符串和反序列化为实例对象 分类: JSON 前端 2014-11-10 10:20 97人阅读 评论(1) 收藏

    一.JSON简介 JSON(JavaScript Object Notation,JavaScript对象表示法)是一种轻量级的数据交换格式. JSON是"名值对"的集合.结构由大 ...

  2. 如何将C#对象转化为JSON字符串

    System.Web.Extensions.dll中类JavaScriptSerializer可以帮助我们把C#对象转化为JSON字符串. 有一个Person类 public class Person ...

  3. python字典转化成json格式。JSONEncoder和JSONDecoder两个类来实现Json字符串和dict类型数据的互相转换

    遇到问题:进行Webservice接口测试时,对接口入参数据进行了处理,变成了dict格式,去进行接口请求报错. 需要转成成json格式,双引号去扩. 如下: 更改代码: # 在Python标准库的j ...

  4. js如何生成一个对象,并转化为json字符串

    js如何生成一个对象,并转化为json字符串,很多人都会误写为: var ary = []; var obj = {}; for (var i = 0; i < 3; i++) { obj.na ...

  5. 前台的js对象数组传到后台处理。在前台把js对象数组转化为json字符串,在后台把json字符串解析为List<>

    前台的js对象数组传到后台处理.在前台把js对象数组转化为json字符串,在后台把json字符串解析为List<>

  6. json字符串转化为json对象and 对象转化为 json字符串

    第一种方法: var data =evel('('+jsonstr+')') 解析:  这种方法是常用的方法, 即动态执行 javascript代码 在堆中存放数据. 存在安全问题. 第二种方法:   ...

  7. 将数组转化为json字符串(不使用json_encode函数)

    将数组转化为json字符串(不使用json_encode函数) public function arrayToJson($arr,$jsonStr=''){ $jsonStr.='{'; foreac ...

  8. js中JSON的解析(将json字符串转化为对象)和序列化(将对象转化为json字符串)(函数的功能一般都挺全的,需要的时候去查看完整函数)

    js中JSON的解析(将json字符串转化为对象)和序列化(将对象转化为json字符串)(函数的功能一般都挺全的,需要的时候去查看完整函数) 一.总结 1.JSON解析:JSON.parse(myJS ...

  9. JS对象转化为JSON字符串

    js方法: JSON.stringify 把一个对象转换成json字符串 JSON.parse 把一个json字符串解析成对象. 实例: var jsObj = {}; jsObj.testArray ...

随机推荐

  1. MVC修改视图的默认路径

    概述:之前MVC5和之前的版本中,我们要想对View文件的路径进行控制的话,则必须要对IViewEngine接口的FindPartialView或FindView方法进行重写,所有的视图引擎都继承于该 ...

  2. JS 字符串 作为变量名

    function initCKEditor(querySelector,content_val,myEditor) { ClassicEditor.create(document.querySelec ...

  3. Lua面向对象 --- 单例

    GameManager.lua: --单例模式是利用一个全局表来实现的 GameManager = {} Manager = {__index = GameManager} function Game ...

  4. win10 自己DIY的arp绑定小脚本

    @echo off&mode con cols=80 lines=22&title ARP_bind Tools setlocal enabledelayedexpansion rem ...

  5. 记一次无法正常本地登陆Linux服务器(确定密码正确)

    首先,ssh可以正常登陆使用.但是,本地可以确定密码是正确的情况还是不能登陆. 然后查看/var/log/secure文件如下提示: 然后,尝试去看了下/etc/pam.d/login 下面(有问题的 ...

  6. LeetCode--204--计数质数

    问题描述: 统计所有小于非负整数 n 的质数的数量. 示例: 输入: 10 输出: 4 解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 . 方法1:经典的判断是否为质数遍历( ...

  7. angularjs 中的scope继承关系——(1)

    转自:http://www.lovelucy.info/understanding-scopes-in-angularjs.html JavaScript 的原型链继承 假设父类 parentScop ...

  8. JavaScript学习总结(六)——JavaScript判断数据类型总结

    最近做项目中遇到了一些关于javascript数据类型的判断处理,上网找了一下资料,并且亲自验证了各种数据类型的判断,在此做一个总结吧! 一.JS中的数据类型 1.数值型(Number):包括整数.浮 ...

  9. Awk 从入门到放弃(5)– Awk模式(Pattern)之一

    转:http://www.zsythink.net/archives/1426

  10. javascript开发HTML5游戏--斗地主(单机模式part2)

    最近学习使用了一款HTML5游戏引擎(青瓷引擎),并用它尝试做了一个斗地主的游戏,简单实现了单机对战和网络对战,代码可已放到github上,在此谈谈自己如何通过引擎来开发这款游戏的. 客户端代码 服务 ...