You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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类型:

  1. 编写自定义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);
        }
    }
}
  1. 注册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类型的数值转换:

  1. 编写自定义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);
    }
}
  1. 注册到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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 20:00:08