如何配置Jackson实现以Java类名为键的对象序列化与反序列化
Jackson适配单键类标识格式的通用解决方案
这个需求可以通过自定义Jackson的通用序列化/反序列化器,注册为全局模块实现,支持所有Java类型的自动适配,不需要为单个字段额外加注解。
核心实现逻辑
第三方返回的格式本质是将对象类型作为唯一键、对象值作为键值的包装结构,我们只需要在序列化/反序列化阶段处理这个包装逻辑即可。
1. 编写通用反序列化器(处理第三方返回的JSON解析)
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.node.ObjectNode; import java.io.IOException; import java.util.Iterator; import java.util.Map; public class ClassWrappedDeserializer extends JsonDeserializer<Object> { @Override public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { ObjectNode node = p.getCodec().readTree(p); // 判断是否为单键值对的包装结构 if (node.size() == 1) { Iterator<Map.Entry<String, JsonNode>> fields = node.fields(); Map.Entry<String, JsonNode> onlyField = fields.next(); String className = onlyField.getKey(); JsonNode valueNode = onlyField.getValue(); try { // 加载类并将值反序列化为对应类型 Class<?> clazz = Class.forName(className); return p.getCodec().treeToValue(valueNode, clazz); } catch (ClassNotFoundException e) { throw new JsonMappingException(p, "无法识别的类类型: " + className, e); } } // 非包装结构走默认反序列化 return p.getCodec().treeToValue(node, Object.class); } }
2. 编写通用序列化器(生成符合第三方要求的JSON格式)
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; public class ClassWrappedSerializer extends JsonSerializer<Object> { @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeStartObject(); // 键为对象类的全限定名 gen.writeFieldName(value.getClass().getName()); // 值为对象本身的序列化结果 gen.writeObject(value); gen.writeEndObject(); } }
3. 注册为全局模块,Spring Boot自动生效
将自定义序列化/反序列化器封装为Jackson模块,Spring Boot会自动扫描注册所有Module类型的Bean:
import com.fasterxml.jackson.databind.module.SimpleModule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.Date; @Configuration public class JacksonConfig { @Bean public SimpleModule classWrappedModule() { SimpleModule module = new SimpleModule("ClassWrappedModule"); // 为需要适配的类型注册序列化/反序列化器,按需添加即可 // 示例添加Date类型支持 module.addSerializer(Date.class, new ClassWrappedSerializer()); module.addDeserializer(Object.class, new ClassWrappedDeserializer()); // 如果需要适配自定义类型,直接追加即可,比如: // module.addSerializer(自定义类.class, new ClassWrappedSerializer()); return module; } }
效果验证
你提供的示例JSON可以直接解析为对应实体类:
// 实体类定义 @Data public class Task { @JsonProperty("task-id") private Long taskId; @JsonProperty("task-created-on") private Date taskCreatedOn; }
解析后taskCreatedOn会自动转换为java.util.Date类型,序列化时也会自动生成{"java.util.Date": 时间戳}的格式。
如果需要适配更多类型,只需要在classWrappedModule方法中追加对应类型的序列化器注册即可,无需修改核心逻辑。
内容的提问来源于stack exchange,提问作者Kenster
相关产品推荐
相关产品推荐

