- 操作环境:
jdk8、gson 2.8.5 - 实验代码
public class TestSerial {
public static void main(String[] args) {
Outer outer = new Outer();
// JsonUtil是自己封装的一个json工具类。
String json = JsonUtil.toJson(outer);
Outer outer1 = JsonUtil.fromJson(json, new TypeToken<Outer>() {
});
System.out.println(outer1);
}
static class Outer {
Inner inner = new Inner();
}
static class Inner {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
}
}
JsonUtil相关代码
public static String toJson(Object target) {
return toJson(target, null, false, null, null, EXCLUDE_FIELDS_WITHOUT_EXPOSE, PRETTY_PRINT);
}
public static String toJson(Object target, Type targetType, boolean isSerializeNulls, Double version, String datePattern, boolean excludesFieldsWithoutExpose, boolean prettyPrint) {
if (target == null) {
return EMPTY_JSON;
}
GsonBuilder builder = new GsonBuilder().setExclusionStrategies(new FilterExclusionStrategy());
if (isSerializeNulls) {
builder.serializeNulls();
}
if (prettyPrint) {
builder.setPrettyPrinting();
}
if (version != null) {
builder.setVersion(version.doubleValue());
}
if (isEmpty(datePattern)) {
datePattern = DEFAULT_DATE_PATTERN;
}
builder.setDateFormat(datePattern);
if (excludesFieldsWithoutExpose) {
builder.excludeFieldsWithoutExposeAnnotation();
}
String result = "";
Gson gson = builder.create();
try {
if (targetType != null) {
result = gson.toJson(target, targetType);
} else {
result = gson.toJson(target);
}
} catch (Exception ex) {
log.error("目标对象 " + target.getClass().getName() + " 转换 JSON 字符串时,发生异常!", ex);
if (target instanceof Collection || target instanceof Iterator || target instanceof Enumeration || target.getClass().isArray()) {
result = EMPTY_JSON_ARRAY;
} else {
result = EMPTY_JSON;
}
}
return result;
}
- 问题结果截图
- 问题分析
我已经声明了Inner类里属性map的数据结构为ConcurrentHashMap为什么在反序列化的时候变成了LinkedTreeMap呢?顺着代码追了一遍发现,这个Map是Gson包下自己定义的一个数据结构。如果没有给嵌套对象指定类型,默认的结果就是LinkedTreeMap。 - 解决方案
- 使用策略模式,给自己定义的待反序列化的类实现自己独有的反序列化方法,其主要的接口为:JsonDeserializer
伪代码:
public class MyDeSerial implements JsonDeserializer<TestSerial.Outer> {
@Override
public TestSerial.Outer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return null;
}
}
- 不使用泛型,可以避免泛型擦除的问题;即将Inner类中的属性,直接生命成对应的数据结构类型,而不使用泛型接口。代码如下:
static class Inner {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
}
- 关于序列化接口的使用,个人觉得它的应用场景只有两个
- 需要持久化到文件中
- 需要进行流传输的
- 诸如Json这样的操作,我们是没有必要实现序列化接口的
- 总结:
- Gson不需要相关类实现Serializable接口
- Gson反序列化嵌套类型的复杂对象会有泛型擦除的可能
- 遇事不要慌、冷静思考终有答案!