You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Jackson序列化时,如何让JSON中Long类型键保持数字而非字符串?

解决Jackson 2.6.2将Long键Map序列化为数字键JSON的问题

我之前也碰到过一模一样的情况!Jackson 2.x默认会把Map的非String类型键转成字符串输出,而且严格遵循JSON规范给键加上双引号。要实现你想要的数字形式键的输出,有两种方案可选,看你的具体需求来:

方案一:全局关闭字段名引号(生成非标准JSON)

如果你的整个JSON输出都不需要给键加双引号,并且能接受非标准的JSON格式(这种格式在JavaScript里能正常解析,但严格的JSON校验工具可能报错),可以直接配置ObjectMapper关闭QUOTE_FIELD_NAMES特性:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.util.HashMap;
import java.util.Map;

public class MapSerializationExample {
    public static void main(String[] args) throws Exception {
        Map<Long, String> processes = new HashMap<>();
        processes.put(1L, "p1");
        processes.put(2L, "p2");

        ObjectMapper mapper = new ObjectMapper();
        // 关闭字段名自动加双引号的特性
        mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
        // 可选:开启格式化输出,让JSON更易读
        mapper.enable(SerializationFeature.INDENT_OUTPUT);

        String json = mapper.writeValueAsString(processes);
        System.out.println(json);
    }
}

运行这段代码后,输出的结果就是你想要的格式:

{
  1 : "p1",
  2 : "p2"
}

⚠️ 注意:这种方式会让所有JSON对象的键都不带引号,如果你有其他String类型的键,也会变成无引号的形式,可能不符合预期。

方案二:自定义序列化器(仅处理Long类型键)

如果你只想让Long类型的键输出为数字形式,其他类型的键仍保持标准的带引号字符串,那可以自定义一个针对Long键的序列化逻辑:

步骤1:创建自定义的Long键序列化器

这个序列化器会专门处理Long类型的键,输出不带引号的数字形式:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;

public class LongKeySerializer extends JsonSerializer<Long> {
    @Override
    public void serialize(Long key, JsonGenerator gen, SerializerProvider provider) throws IOException {
        // 直接写入数字形式的键,绕过默认的引号添加逻辑
        gen.writeRaw(key.toString());
        gen.writeRaw(": ");
    }
}

步骤2:创建针对Long键Map的序列化器

为了完整控制Map的序列化过程,我们再写一个专门处理Map<Long, String>的序列化器:

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.util.Map;

public class LongKeyMapSerializer extends JsonSerializer<Map<Long, String>> {
    @Override
    public void serialize(Map<Long, String> map, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeStartObject();
        boolean firstEntry = true;
        for (Map.Entry<Long, String> entry : map.entrySet()) {
            if (!firstEntry) {
                gen.writeRaw(", ");
            }
            // 使用自定义Long键序列化器写入键
            new LongKeySerializer().serialize(entry.getKey(), gen, serializers);
            // 写入带引号的值
            gen.writeString(entry.getValue());
            firstEntry = false;
        }
        gen.writeEndObject();
    }
}

步骤3:注册序列化器并使用

把自定义序列化器注册到ObjectMapper中,或者直接在Map字段上添加注解:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.util.HashMap;
import java.util.Map;

public class CustomSerializationExample {
    public static void main(String[] args) throws Exception {
        Map<Long, String> processes = new HashMap<>();
        processes.put(1L, "p1");
        processes.put(2L, "p2");

        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        // 注册自定义的Map序列化器
        module.addSerializer(new LongKeyMapSerializer());
        mapper.registerModule(module);
        // 可选:开启格式化输出
        mapper.enable(SerializationFeature.INDENT_OUTPUT);

        String json = mapper.writeValueAsString(processes);
        System.out.println(json);
    }
}

这样输出的结果同样是数字形式的Long键,而且只会影响Map<Long, String>类型的序列化,其他类型的键不受影响。

额外说明

严格来说,JSON规范要求对象的键必须是带双引号的字符串,你想要的{ 1: "p1", 2: "p2" }其实更接近JavaScript对象字面量,而非标准JSON。如果你的场景需要和严格遵循JSON规范的系统交互,建议还是保留字符串形式的键——反序列化的时候,Jackson会自动把字符串键转换为Long类型,完全不影响使用。

内容的提问来源于stack exchange,提问作者Sagar Pudi

火山引擎 最新活动