如何基于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
相关产品推荐
相关产品推荐

