防止 Gson 将整数(Integer)表示为浮点数(Float)
1、简介
在将 Java 对象序列化和反序列化为 JSON 格式或从 JSON 格式反序列化 Java 对象时,Google 开发的 Gson 库是一个不错的选择。但是,在序列化对象时,我们通常会遇到 Gson 将整数显示为浮点数的问题。
本文将带你了解为什么在 Gson 的设计中整数被视为浮点数?以及如何解决这个问题。
2、问题的定义
Gson 可将 Java 对象序列化为 JSON。默认情况下,Gson 会将整数序列化为浮点数,以获得更精确的表示。下面是一个简单的例子:
public String jsonString= "[{\"id\":4077395,\"field_id\":242566,\"body\":\"\"}, " +
"{\"id\":4077398,\"field_id\":242569,\"body\":[[273019,0],[273020,1],[273021,0]]}, " +
"{\"id\":4077399,\"field_id\":242570,\"body\":[[273022,0],[273023,1],[273024,0]]}]";
如上,我们声明了一个名为 jsonString
的 JSON 字符串,它代表一个对象数组。这个 JSON 数组有不同的字段,如 id
、field_id
和 body
。
现在,我们使用 Gson 库将 JSON 字符串反序列化为 Hashtable<String, Object>
对象列表。
ArrayList<Hashtable<String, Object>> responses;
Type ResponseList = new TypeToken<ArrayList<Hashtable<String, Object>>>() {}.getType();
responses = new Gson().fromJson(jsonString, ResponseList);
如上,我们声明了一个名为 responses
的 ArrayList
,其中包含 Key 为字符串、Value 为对象的 Hashtable
类型元素。此外,我们还利用 Gson 库将 jsonString
反序列化为 Hashtables
列表。
最后,我们在反序列化过程中使用 TypeToken
获取泛型类型信息。
格式化后的 responses
如下:
[{
body = ,
field_id = 242566.0,
id = 4077395.0
}, {
body = [
[273019.0, 0.0],
[273020.0, 1.0],
[273021.0, 0.0]
],
field_id = 242569.0,
id = 4077398.0
}, {
body = [
[273022.0, 0.0],
[273023.0, 1.0],
[273024.0, 0.0]
],
field_id = 242570.0,
id = 4077399.0
}]
注意,Gson 将整数表示为浮点数。
3、Gson 的默认数字策略(Number Strategy)
Gson 的默认数字策略旨在在表示数值时在准确性和灵活性之间取得平衡。将整数使用浮点数来表示的决策基于 JSON 缺乏明确支持区分整数和浮点数类型的能力。因此,Gson 选择了默认策略,以确保数值的精度保持不变。
但是,这种默认行为可能不符合特定要求或偏好,尤其是在处理 JSON 表示法中整数应保持整数的情况时。
4、使用 setObjectToNumberStrategy() 方法
利用 Gson 的 setObjectToNumberStrategy()
方法,我们可以在反序列化过程中彻底控制对象到数字转换机制的功能。
让我们通过一个示例来了解这种功能:
public static String expectedOutput ="[{body=, field_id=242566, id=4077395}, " +
"{body=[[273019, 0], [273020, 1], [273021, 0]], field_id=242569, id=4077398}, " +
"{body=[[273022, 0], [273023, 1], [273024, 0]], field_id=242570, id=4077399}]";
@Test
public void givenJsonString_whenUsingsetObjectToNumberStrategyMethod_thenValidateOutput() {
Gson gson = new GsonBuilder()
.setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE)
.create();
ArrayList<Hashtable<String, Object>> responses = gson.fromJson(jsonString,
new TypeToken<ArrayList<Hashtable<String, Object>>>() {}.getType());
assertEquals(expectedOutput, responses.toString());
}
如上,通过使用 setObjectToNumberStrategy()
方法,我们可以为 Gson 设置 ToNumberPolicy.LONG_OR_DOUBLE
等策略,以指定其处理数值的行为。最后,使用 assertEquals()
方法验证转换过程。
此外,Gson 的 ToNumberPolicy
枚举支持多种处理数值的策略。除了我们在示例中使用的 ToNumberPolicy.LONG_OR_DOUBLE
之外,其他策略包括:
- ToNumberPolicy.DOUBLE_ONLY: 在反序列化过程中将所有数值转换为 double。
- ToNumberPolicy.LONG_ONLY: 在反序列化过程中将所有数值转换为 long
- ToNumberPolicy.DEFAULT: 保留 Gson 的默认行为,将整数表示为浮点数
5、总结
本文介绍了使用 Gson 时遇到的一个问题:在序列化过程中,整数会自动转换为浮点数,以及如何通过 setObjectToNumberStrategy()
方法来自定义数值的序列化和反序列化策略。
Ref:https://www.baeldung.com/java-gson-prevent-expressing-integers-as-floats