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

如何基于Jackson实现Java静态final实例层级的通用序列化与反序列化

通用常量类的Jackson序列化与反序列化实现

现有常量类结构

以下是定义的三个Java类:

public class Base {
    private int code;
    private static final Map<String, Map<Integer, Base>> ALL_MAPS = new HashMap<>();

    protected Base(int code) {
        this.code = code;
        getConstMap(this.getClass()).put(code, this);
    }

    protected Map<Integer, Base> getConstMap(Class<?> clazz) {
        Map<Integer, Base> res;
        if ((res = ALL_MAPS.get(clazz.getName())) == null) {
            res = new HashMap<>();
            ALL_MAPS.put(clazz.getName(), res);
        }
        return res;
    }
    // 其他省略方法
}

public class AConstants extends Base {
    public static final AConstants A_1 = new AConstants(1, "sample1");
    public static final AConstants A_2 = new AConstants(2, "sample2");
    // 其他省略常量
    private final String text;

    private AConstants(int code, String text) {
        super(code);
        this.text = text;
    }
}

public class BConstants extends Base {
    public static final BConstants B_1 = new BConstants(1, "sample1", "moreText");
    public static final BConstants B_2 = new BConstants(2, "sample2", "moreText");
    // 其他省略常量
    private final String text;
    private final String moreText;

    private BConstants(int code, String text, String moreText) {
        super(code);
        this.text = text;
        this.moreText = moreText;
    }
}

需求与问题

希望在Base类中实现通用的序列化和反序列化逻辑:将静态常量实例序列化为对应的code值,反序列化时通过code还原为对应常量实例。但由于静态方法无法在编译时获取子类泛型类型,无法直接写出如下通用代码:

@JsonCreator
public static CONST deserialize(@JsonProperty("code") int code) {
    // 无法直接获取CONST的类对象
    return ALL_MAPS.get(CONST.class).get(code);
}

@JsonValue
public Integer serialize() {
    // 无法直接获取CONST的类对象
    return getKeyByValue(ALL_MAPS.get(CONST.class), this);
}

解决方案

1. 通用序列化实现(基于@JsonValue)

序列化逻辑可直接通过@JsonValue注解实现,在Base类中添加返回code的方法即可,Jackson会自动将实例序列化为对应code值:

public class Base {
    // ... 原有代码 ...

    @JsonValue
    public int getCode() {
        return this.code;
    }
}

此时AConstants.A_1会被序列化为1,BConstants.B_2会被序列化为2,无需子类额外处理。

2. 通用反序列化实现(自定义反序列化器)

由于静态方法无法动态获取目标子类类型,需自定义通用反序列化器,利用Jackson的DeserializationContext获取目标Class,再从全局ALL_MAPS中取出对应常量实例。

第一步:编写通用反序列化器

public class ConstantsDeserializer extends StdDeserializer<Base> {

    protected ConstantsDeserializer() {
        super(Base.class);
    }

    @Override
    public Base deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        // 获取当前要反序列化的目标类型
        Class<?> targetClass = ctxt.getContextualType().getRawClass();
        int code = p.getValueAsInt();
        // 从全局Map中取出对应常量实例
        Map<Integer, Base> constantsMap = Base.ALL_MAPS.get(targetClass.getName());
        if (constantsMap == null || !constantsMap.containsKey(code)) {
            throw new IOException("无效的code值: " + code + " 对应类型: " + targetClass.getName());
        }
        return constantsMap.get(code);
    }
}

第二步:注册反序列化器

有两种注册方式可选:

  • 注解式注册:在Base类上添加@JsonDeserialize注解,指定使用自定义反序列化器,所有子类会自动继承该配置:
    @JsonDeserialize(using = ConstantsDeserializer.class)
    public class Base {
        // ... 原有代码 ...
    }
    
  • 全局注册:在初始化ObjectMapper时全局注册反序列化器,无需修改Base类注解:
    ObjectMapper objectMapper = new ObjectMapper();
    SimpleModule module = new SimpleModule();
    module.addDeserializer(Base.class, new ConstantsDeserializer());
    objectMapper.registerModule(module);
    

3. 功能验证示例

public class Test {
    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();

        // 序列化测试
        String a1Json = mapper.writeValueAsString(AConstants.A_1);
        System.out.println(a1Json); // 输出: 1

        // 反序列化测试
        AConstants a1 = mapper.readValue("1", AConstants.class);
        System.out.println(a1 == AConstants.A_1); // 输出: true

        String b2Json = mapper.writeValueAsString(BConstants.B_2);
        System.out.println(b2Json); // 输出: 2

        BConstants b2 = mapper.readValue("2", BConstants.class);
        System.out.println(b2 == BConstants.B_2); // 输出: true
    }
}

注意事项

  • 确保所有常量实例在反序列化前已完成初始化(静态常量会在类加载时初始化,只需确保类已被加载即可)。
  • 不同子类的code值不会冲突,因为ALL_MAPS是按类名区分存储的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 01:47:51