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

代码形如:

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

程序输出内容为:

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

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

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

程序输出内容为:

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) 这个方法,实现如下:

  /**
* Writes the JSON representation of {@code src} of type {@code typeOfSrc} to
* {@code writer}.
* @throws JsonIOException if there was a problem writing to the writer
*/
@SuppressWarnings("unchecked")
public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc));
boolean oldLenient = writer.isLenient();
writer.setLenient(true);
boolean oldHtmlSafe = writer.isHtmlSafe();
writer.setHtmlSafe(htmlSafe);
boolean oldSerializeNulls = writer.getSerializeNulls();
writer.setSerializeNulls(serializeNulls);
try {
((TypeAdapter<Object>) adapter).write(writer, src);
} catch (IOException e) {
throw new JsonIOException(e);
} finally {
writer.setLenient(oldLenient);
writer.setHtmlSafe(oldHtmlSafe);
writer.setSerializeNulls(oldSerializeNulls);
}
}

进入getAdapter方法

 public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
TypeAdapter<?> cached = typeTokenCache.get(type);
if (cached != null) {
return (TypeAdapter<T>) cached;
} Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false;
if (threadCalls == null) {
threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
} // the key and value type parameters always agree
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
} try {
FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
threadCalls.put(type, call); for (TypeAdapterFactory factory : factories) {
TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) {
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}
throw new IllegalArgumentException("GSON cannot handle " + type);
} finally {
threadCalls.remove(type); if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
 

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

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

  public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
Class<?> rawType = type.getRawType();
final boolean skipSerialize = excludeClass(rawType, true);
final boolean skipDeserialize = excludeClass(rawType, false); if (!skipSerialize && !skipDeserialize) {
return null;
} return new TypeAdapter<T>() {
/** The delegate is lazily created because it may not be needed, and creating it may fail. */
private TypeAdapter<T> delegate; @Override public T read(JsonReader in) throws IOException {
if (skipDeserialize) {
in.skipValue();
return null;
}
return delegate().read(in);
} @Override public void write(JsonWriter out, T value) throws IOException {
if (skipSerialize) {
out.nullValue();
return;
}
delegate().write(out, value);
} private TypeAdapter<T> delegate() {
TypeAdapter<T> d = delegate;
return d != null
? d
: (delegate = gson.getDelegateAdapter(Excluder.this, type));
}
};
}

这里

  public boolean excludeClass(Class<?> clazz, boolean serialize) {
if (version != Excluder.IGNORE_VERSIONS
&& !isValidVersion(clazz.getAnnotation(Since.class), clazz.getAnnotation(Until.class))) {
return true;
} if (!serializeInnerClasses && isInnerClass(clazz)) {
return true;
} if (isAnonymousOrLocal(clazz)) {
return true;
} List<ExclusionStrategy> list = serialize ? serializationStrategies : deserializationStrategies;
for (ExclusionStrategy exclusionStrategy : list) {
if (exclusionStrategy.shouldSkipClass(clazz)) {
return true;
}
} return false;
}

这里调用了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. 使用tk.mybatis快速开发curd

    使用mybatis已经是可以快速开发程序了,对于单表的curd似乎是一种可抽象的结果,下面介绍tk.mybatis的使用方式. maven引用 我使用的是这个版本,所以相关功能介绍也是这个版本. 使用 ...

  2. tp3.x和tp 5的区别

    由于TP5.0是一个全新的颠覆重构版本,所以现在面试很多面试官喜欢问TP3.2和TP5之间的区别,那他们之间到底有哪些区别呢?一.目录  TP5目录 二.需要摒弃的 3.X 旧思想 模型的变动     ...

  3. nodejs 监听文件夹变化的模块

    使用Node.JS监听文件夹变化 fs.watch 其中Node.JS的文件系统也可侦听某个目录的改变, 如fs.watch   其中fs.watch的最大缺点就是不支持子文件夹的侦听,并且在很多情况 ...

  4. 关于 [TNS-12516 TNS:listener could not find instance with matching protocol stack ]

    Title: Intermittent TNS-12516 or TNS-12519 Errors Connecting Via Net Symptom(s) ~~~~~~~~~~ Client co ...

  5. temp table

    在Oracle8i或以上版本中,可以创建以下两种临时表: 1.会话特有的临时表 CREATE GLOBAL TEMPORARY <TABLE_NAME> ( <column spec ...

  6. 20170728xlVba还是这个混蛋

    Public Sub Main22() If Now() >= #1/1/2018# Then Exit Sub Dim strText As String Dim Reg As Object, ...

  7. 20170714xlVba多个工作簿转多个Word文档表格

    Public Sub SameFolderGather() Application.ScreenUpdating = False Application.DisplayAlerts = False A ...

  8. android--------WebView实现 Html5 视频标签加载

    自Android 4.4起,Android中的WebView开始基于Chromium(谷歌浏览器)支持浏览器的一系列功能,webkit解析网页各个节点,这个改变,使得WebView的性能大幅度提升,并 ...

  9. Razor及HtmlHelper学习笔记

    Razor 不是编程语言.它是服务器端标记语言. 什么是Razor? Razor 是一种允许您向网页中嵌入基于服务器的代码(Visual Basic 和 C#)的标记语法. 当网页被写入浏览器时,基于 ...

  10. AIM Tech Round 3 (Div. 1) (构造,树形dp,费用流,概率dp)

    B. Recover the String 大意: 求构造01字符串使得子序列00,01,10,11的个数恰好为$a_{00},a_{01},a_{10},a_{11}$ 挺简单的构造, 注意到可以通 ...