在 Java 开发中,我们经常使用 Map<String, Object>
来存储不同类型的值,并通过 Fastjson 进行序列化和反序列化。然而,在反序列化时,Object
类型的值可能会发生变化,比如 Long
变成 Integer
,导致数据不一致。本文将探讨 Fastjson 如何保证 Object
类型的一致性,并提供相应的解决方案。
1. Fastjson 默认的序列化和反序列化行为
(1)基本数据类型的处理
Fastjson 默认可以正确处理 Java 的基本数据类型,例如 Integer
、Long
、Double
、String
等。
示例
import com.alibaba.fastjson.JSON; import java.util.HashMap; import java.util.Map; public class FastjsonExample { public static void main(String[] args) { Map<String, Object> data = new HashMap<>(); data.put("intValue", 100); data.put("longValue", 100L); data.put("doubleValue", 99.99); data.put("stringValue", "Hello, Fastjson"); // 序列化 String json = JSON.toJSONString(data); System.out.println("Serialized JSON: " + json); // 反序列化 Map<String, Object> deserializedData = JSON.parseObject(json, Map.class); System.out.println("Deserialized Map: " + deserializedData); } }
输出
Serialized JSON: {"doubleValue":99.99,"intValue":100,"longValue":100,"stringValue":"Hello, Fastjson"} Deserialized Map: {doubleValue=99.99, intValue=100, longValue=100, stringValue=Hello, Fastjson}
问题:
- 在反序列化时,
longValue
变成了Integer
,因为 JSON 默认会将没有超出Integer.MAX_VALUE
的整数解析为Integer
。 - 这可能导致
Object
的类型与原始类型不匹配,影响后续的类型转换。
2. 解决方案
方案 1:使用 SerializerFeature.WriteClassName
记录类型信息
Fastjson 提供了 SerializerFeature.WriteClassName
选项,可以在 JSON 序列化时添加 @type
字段,记录对象的实际类型。这样在反序列化时,Fastjson 可以根据 @type
字段恢复原始类型。
示例
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; import java.util.HashMap; import java.util.Map; public class FastjsonTypeInfoExample { public static void main(String[] args) { Map<String, Object> data = new HashMap<>(); data.put("intValue", 100); data.put("longValue", 100L); data.put("doubleValue", 99.99); data.put("stringValue", "Hello, Fastjson"); // 序列化时记录类型信息 String json = JSON.toJSONString(data, SerializerFeature.WriteClassName); System.out.println("Serialized JSON with type info: " + json); // 反序列化 Map<String, Object> deserializedData = JSON.parseObject(json, Map.class); System.out.println("Deserialized Map: " + deserializedData); System.out.println("Type of longValue: " + deserializedData.get("longValue").getClass().getName()); } }
输出
Serialized JSON with type info: { "doubleValue":{"@type":"java.lang.Double","value":99.99}, "intValue":{"@type":"java.lang.Integer","value":100}, "longValue":{"@type":"java.lang.Long","value":100}, "stringValue":{"@type":"java.lang.String","value":"Hello, Fastjson"} } Deserialized Map: {doubleValue=99.99, intValue=100, longValue=100, stringValue=Hello, Fastjson} Type of longValue: java.lang.Long
优点:
- 反序列化后,
longValue
仍然是Long
,不会变成Integer
。 - 适用于
Map<String, Object>
场景,确保Object
类型数据不丢失。
缺点:
- JSON 变长了,增加了额外的
@type
信息。 - 可能导致 JSON 解析时需要额外的安全处理(防止
@type
被恶意篡改)。
方案 2:使用 parseObject
指定反序列化目标类型
如果你不想在 JSON 里记录 @type
,但仍然希望在反序列化时确保 Object
类型正确,你可以显式指定 TypeReference<Map<String, Object>>
,避免 Fastjson 自动推断类型。
示例
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import java.util.HashMap; import java.util.Map; public class FastjsonTypeReferenceExample { public static void main(String[] args) { Map<String, Object> data = new HashMap<>(); data.put("longValue", 100L); // 序列化 String json = JSON.toJSONString(data); System.out.println("Serialized JSON: " + json); // 使用 TypeReference 反序列化 Map<String, Object> deserializedData = JSON.parseObject(json, new TypeReference<Map<String, Object>>() {}); System.out.println("Type of longValue: " + deserializedData.get("longValue").getClass().getName()); } }
输出
Serialized JSON: {"longValue":100} Type of longValue: java.lang.Long
优点:
- 不需要修改 JSON 格式,减少额外的
@type
信息。 - 避免
Long
变成Integer
,保证数据一致性。
缺点:
- 适用于固定结构的 Map,不能用于复杂的对象层次结构。
3. 总结
方案 | 方式 | 适用场景 | 优缺点 |
---|---|---|---|
默认行为 | JSON.parseObject(json, Map.class) | 适用于大多数情况,但可能导致 Long 变 Integer | 可能导致 Object 类型不一致 |
WriteClassName | JSON.toJSONString(obj, SerializerFeature.WriteClassName) | 适用于 Map<String, Object> ,需要保存类型信息 | JSON 变长,可能存在安全风险 |
TypeReference | JSON.parseObject(json, new TypeReference<Map<String, Object>>() {}) | 适用于 Map,且不想修改 JSON 结构 | 不能处理复杂的多态对象 |
在实际应用中:
- 如果你希望 严格保持
Object
的类型,建议使用SerializerFeature.WriteClassName
方案。 - 如果你 不想修改 JSON 格式,但仍然想保证
Long
不变成Integer
,可以使用TypeReference
。
通过合理选择序列化和反序列化策略,你可以确保 Fastjson 处理 Map<String, Object>
时不会丢失 Object
类型信息,从而提高数据一致性和安全性。