如何用Jackson将Key/Value结构的JSON反序列化为Java对象?
通用Jackson反序列化方案:将Attributes结构JSON映射到Java对象
针对你遇到的这种把字段包装在attributes数组中的非标准JSON,我们可以通过自定义Jackson反序列化器+BeanDeserializerModifier实现通用映射,无需为每个Java类编写单独逻辑,同时支持嵌套结构。
核心实现思路
- 自定义
AttributesDeserializer:负责解析attributes数组,将key-value结构转换为标准的键值对JSON结构,递归处理嵌套的attributes对象。 - 通过
BeanDeserializerModifier全局注册这个反序列化器,让所有自定义JavaBean自动应用该逻辑。
代码实现
1. 通用Attributes反序列化器
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import java.io.IOException; import java.util.Iterator; public class AttributesDeserializer extends JsonDeserializer<Object> { private final ObjectMapper objectMapper; public AttributesDeserializer(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode rootNode = p.getCodec().readTree(p); // 识别并处理attributes包裹的结构 if (rootNode.has("attributes")) { JsonNode attributesNode = rootNode.get("attributes"); ObjectNode targetNode = objectMapper.createObjectNode(); Iterator<JsonNode> attrIterator = attributesNode.elements(); while (attrIterator.hasNext()) { JsonNode attr = attrIterator.next(); String fieldKey = attr.get("key").asText(); JsonNode fieldValue = attr.get("value"); // 递归处理嵌套的attributes结构 if (fieldValue.isObject() && fieldValue.has("attributes")) { fieldValue = deserializeNestedValue(fieldValue, ctxt); } targetNode.set(fieldKey, fieldValue); } // 将转换后的节点映射为目标Java类 return objectMapper.treeToValue(targetNode, ctxt.getContextualType().getRawClass()); } // 非attributes结构直接映射(兼容标准JSON) return objectMapper.treeToValue(rootNode, ctxt.getContextualType().getRawClass()); } private JsonNode deserializeNestedValue(JsonNode valueNode, DeserializationContext ctxt) throws IOException { Object nestedObj = deserialize(valueNode.traverse(objectMapper), ctxt); return objectMapper.valueToTree(nestedObj); } }
2. 全局注册反序列化器
通过BeanDeserializerModifier将自定义反序列化器应用到所有JavaBean:
import com.fasterxml.jackson.databind.BeanDescription; import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; public class AttributesDeserializerModifier extends BeanDeserializerModifier { private final ObjectMapper objectMapper; public AttributesDeserializerModifier(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) { // 跳过Java原生类,只对自定义Bean应用 if (beanDesc.getBeanClass().isPrimitive() || beanDesc.getBeanClass().equals(String.class)) { return deserializer; } return new AttributesDeserializer(objectMapper); } }
3. 使用示例
配置ObjectMapper并测试嵌套JSON的解析:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; public class JacksonDemo { public static void main(String[] args) throws Exception { ObjectMapper objectMapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.setDeserializerModifier(new AttributesDeserializerModifier(objectMapper)); objectMapper.registerModule(module); // 包含嵌套结构的测试JSON String testJson = "{ \"attributes\": [\n" + " { \"key\": \"name\", \"value\": \"Jane\" },\n" + " { \"key\": \"age\", \"value\": 34 },\n" + " { \"key\": \"address\", \"value\": {\n" + " \"attributes\": [\n" + " { \"key\": \"street\", \"value\": \"123 Main St\" },\n" + " { \"key\": \"city\", \"value\": \"New York\" }\n" + " ]\n" + " } }\n" + "]}"; Person person = objectMapper.readValue(testJson, Person.class); System.out.println("姓名: " + person.name); System.out.println("年龄: " + person.age); System.out.println("街道: " + person.address.street); System.out.println("城市: " + person.address.city); } // 自定义JavaBean static class Person { String name; Integer age; Address address; } static class Address { String street; String city; } }
方案优势
- 通用性:无需为每个Java类编写自定义反序列化代码,全局生效
- 嵌套支持:递归处理value中的
attributes结构,适配复杂层级的JSON - 兼容性:同时支持标准JSON格式的解析,不影响原有业务逻辑
内容的提问来源于stack exchange,提问作者Matthew Buckett
相关产品推荐
相关产品推荐

