Gson转化的类包含list变量时,如果直接使用new Gson().toJson(MyClass); 进行转化为Json 字符串内容,list对象的内容会为空。
1、解决方法一:
new Gson().toJsonTree(MyClass).toString();2、解决方法二:
getGson().toJson(MyClass).toString();
本次修改也可以彻底解决 Gson 将 int 转换为 double 的问题。
Gson 中默认处理数值转换的类为 com.google.gson.internal.bind.ObjectTypeAdapter,我们只需要在内存中将其替换即可。
ObjectTypeAdapter 在创建的 Gson 对象中是不存在的,其使用了内部的工厂对象(FACTORY)动态创建。
而 FACTORY 会在 Gson 的构造函数中加入 factories 对象中。
最终,factories 对象通过 Collections 的方法变为不可变列表后保存为成功变量。
我们只需要把 Gson 实例中的 factories 对象内部的工厂对象取代即可。
public final class MapTypeAdapter extends TypeAdapter
其实改动部分只有对 NUMBER 分支的细化,将原始数据是否包含小数点来作为其是否为整数与小数的依据。 我认为原始数据中字面值为 1.0 的数是小数,而字面值为 1 的数为整数。你也可以有自己的实现方式。
第二步,使用自定义工厂方法取代 Gson 实例中的工厂方法。 public Gson getGson() {
Gson gson = new GsonBuilder().create();
try {
Field factories = Gson.class.getDeclaredField("factories");
factories.setAccessible(true);
Object o = factories.get(gson);
Class>[] declaredClasses = Collections.class.getDeclaredClasses();
for (Class c : declaredClasses) {
if ("java.util.Collections$UnmodifiableList".equals(c.getName())) {
Field listField = c.getDeclaredField("list");
listField.setAccessible(true);
List list = (List) listField.get(o);
int i = list.indexOf(ObjectTypeAdapter.FACTORY);
list.set(i, MapTypeAdapter.FACTORY);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return gson;
}
代码中,首先获得 gson 实例的 factories 属性,将属性设置为 public 访问权限,然后获得其属性 o。
因为在 gson 的创建过程中,factories 通过 Collections 的方法变为了不可修改对象,所以我们需要将其真实属性获得才能进行修改。
通过 Collections 的字节码对象获得其声明的所有内部类,遍历内部类获得 UnmodifiableList 类的字节码对象,最后获得其进行包装之前的真实列表数据 listField,并设置其访问权限为 public。
最终获得了真实的 factories 列表 list。
最后一步,得到 ObjectTypeAdapter.FACTORY 在列表中的位置,并用自定义的工厂对象取代之。需要注意的是,必须要将工厂对象同位置替换,因为解析优先级是和列表中的位置有关的。



