Java:JSON元素转Object时Integer被转为Double,如何修改默认行为?
解决Object类型反序列化时数值自动转为Double的问题
问题原因
JSON本身没有区分整数(Integer)和浮点数(Double)的原生类型,所有数值都统一用JSON数值类型表示。当Gson或Jackson将JSON数值反序列化到Object类型的字段时,默认会选择兼容性更强的Double类型,这就导致原本的Integer值被转成了Double(比如1变成1.0)。
Gson解决方案:自定义TypeAdapter
通过自定义TypeAdapter来处理Object类型的反序列化,根据数值的格式判断是整数还是浮点数,分别转换为对应的Java类型:
- 编写自定义TypeAdapter:
public class ObjectNumericTypeAdapter extends TypeAdapter<Object> { @Override public void write(JsonWriter out, Object value) throws IOException { if (value instanceof Number) { if (value instanceof Integer) { out.value((Integer) value); } else { out.value((Double) value); } } else { new Gson().toJson(value, out); } } @Override public Object read(JsonReader in) throws IOException { JsonToken token = in.peek(); switch (token) { case NUMBER: String numStr = in.nextString(); // 判断是否包含小数或科学计数法,区分整数和浮点数 if (numStr.contains(".") || numStr.matches("[+-]?\\d+[eE][+-]?\\d+")) { return Double.parseDouble(numStr); } else { // 处理整数,超出Integer范围则转Long try { return Integer.parseInt(numStr); } catch (NumberFormatException e) { return Long.parseLong(numStr); } } case STRING: return in.nextString(); case BOOLEAN: return in.nextBoolean(); case NULL: in.nextNull(); return null; case BEGIN_OBJECT: return new Gson().fromJson(in, Map.class); case BEGIN_ARRAY: return new Gson().fromJson(in, List.class); default: throw new IOException("Unexpected token: " + token); } } }
- 注册TypeAdapter到Gson:
// 创建Gson实例时注册自定义适配器 Gson gson = new GsonBuilder() .registerTypeAdapter(Object.class, new ObjectNumericTypeAdapter()) .create(); // 后续转换代码不变 JsonElement jsonElement = gson.toJsonTree(fieldMap); Field field = gson.fromJson(jsonElement, Field.class); // 此时field.value为Integer类型的1
Jackson解决方案:自定义Deserializer
同样通过自定义反序列化器来处理Object类型的数值转换:
- 编写自定义Deserializer:
public class ObjectNumericDeserializer extends JsonDeserializer<Object> { @Override public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonToken token = p.getCurrentToken(); if (token == JsonToken.VALUE_NUMBER_INT) { // 优先转为Integer,超出范围自动转Long return p.getNumberValue(); } else if (token == JsonToken.VALUE_NUMBER_FLOAT) { return p.getDoubleValue(); } // 其他类型按默认逻辑处理 return ctxt.readValue(p, Object.class); } }
- 注册到ObjectMapper:
ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addDeserializer(Object.class, new ObjectNumericDeserializer()); mapper.registerModule(module); // 使用改造后的ObjectMapper进行转换 Field field = mapper.convertValue(f1, Field.class); // 此时field.value为Integer类型的1
补充说明
如果你的场景中需要严格区分整数和浮点数,上述自定义适配器可以根据实际需求调整(比如强制所有整数转Integer,或者根据数值大小选择Integer/Long)。另外,若你的Field类可以修改,也可以考虑将value字段的类型从Object改为泛型或具体数值类型,从根源避免类型转换问题。
内容的提问来源于stack exchange,提问作者Santhosh mp
相关产品推荐
相关产品推荐

