Circular references
question:循环引用会引起stack overflow
solution:这个目前gson(2.8.5)都没有解决,推荐YaGson
,是gson的一个fork,用法相同。
<dependency>
<groupId>com.gilecode.yagson</groupId>
<artifactId>yagson</artifactId>
<version>0.4.1</version>
</dependency>
https://github.com/amogilev/yagson/blob/master/UserGuide.adoc
异常
java.lang.IllegalArgumentException: Infinity is not a valid double value as per JSON specification. To override this behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method.
reason:如果你传入 Float.POSITIVE_INFINITY 值,Gson 将会抛出异常,因为这个值是不能符合 JSON 标准的。
solution:通过 GsonBuilder 设置 serializeSpecialFloatingPointValues() 。
example:
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.serializeSpecialFloatingPointValues() // 这是关键
.create();
https://www.jianshu.com/p/83eb1b2bc119
java.lang.IllegalArgumentException: JSON forbids NaN
and infinities: NaN
test:在这里无论是gson
还是YaGson
都是报错。
@Test
public void testInfinity2() {
Map map = new HashMap();
map.put(Double.NaN, "x");
Gson gson = new YaGsonBuilder()
.setPrettyPrinting()
// .enableComplexMapKeySerialization()
.serializeSpecialFloatingPointValues()
.create();
String json = gson.toJson(map);
log.info(json);
Map map2 = gson.fromJson(json, HashMap.class);
}
https://github.com/ar-android/google-gson/issues/639
reason:虽然GsonBuilder
可以通过setLenient将JsonWriter.lenient = true
:
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.setLenient() // here
.serializeSpecialFloatingPointValues()
.create();
但是JsonTreeWriter.lenient
仍然是false
。(JsonTreeWriter
继承自JsonWriter
),通过查看源码得知原因:
TypeAdapter类:
public final JsonElement toJsonTree(T value, WriteContext ctx) {
try {
// new的JsonTreeWriter.lenient为false,此后再无更改
JsonTreeWriter jsonWriter = new JsonTreeWriter();
write(jsonWriter, value, ctx);
return jsonWriter.get();
} catch (IOException e) {
throw new JsonIOException(e);
}
}
这就没办法了,只能改源码(未经过全面检测,后果自负):
JsonTreeWriter类:
public JsonTreeWriter() {
super(UNWRITABLE_WRITER);
this.setLenient(true); // here,简单粗暴
}
类型接管
注意:
ImmutableList
序列化的类型实际是RegularImmutableList
,不能使用父类ImmutableList
来替上面的子类型RegularImmutableList
。可以使用registerTypeHierarchyAdapter
,方法同registerTypeAdapter
。
https://www.jianshu.com/p/3108f1e44155
对于又有Circular references
又有ImmutableList
类型的成员反序列化,只能改YaGson源码。
以下是正常反序列化
com.google.gson.internal.bind
CollectionTypeAdapterFactory.readOptionallyAdvisedInstance line257
MapTypeAdapterFactory.readOptionallyAdvisedInstance line239
以下是引用变量的反序列化
com.google.gson.internal.bind
ReflectiveTypeAdapterFactory$DefaultBoundField
// 加入了对各种guava不变类的判断
protected void applyReadFieldValue(Object value, Object fieldValue) throws IllegalAccessException {
if (fieldValue != null || !isPrimitive) {
Class clazz = field.getType();
if (clazz.equals(ImmutableList.class)) {
field.set(value, ImmutableList.copyOf((Collection<?>) fieldValue));
} else if (clazz.equals(ImmutableSet.class)) {
field.set(value, ImmutableSet.copyOf((Collection<?>) fieldValue));
} else if (clazz.equals(ImmutableMap.class)) {
field.set(value, ImmutableMap.copyOf((Map<?, ?>) fieldValue));
} else {
field.set(value, fieldValue);
}
}
}
网友评论