如何通过注解或自定义序列化器将JSON键映射为Java对象的name属性
问题描述
我有一段需要序列化和反序列化的JSON数据:
{ "name1": { "key1": "value1", "key2": "value2" } }
能否通过注解或自定义(反)序列化器,将JSON中的外层键(例如"name1")作为Java对象的name属性?当前使用的Java代码如下:
@lombok.Data public class Example { private String name; private Map<String,String> properties = new HashMap<>(); public Example(String name) { this.name = name; } public void add(String attr1, String val1) { properties.put(attr1, val1); } public static void main(String[] args) throws JsonProcessingException { Example bean = new Example("name1"); bean.add("key1", "value1"); bean.add("key2", "value2"); String result = new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(bean); System.out.println(result); } }
未做任何配置时的输出结果为:
{ "name" : "name1", "properties" : { "key1" : "value1", "key2" : "value2" } }
解决方案
要实现这种动态键与Java对象属性的映射,需为Example类自定义Jackson的序列化器和反序列化器,具体步骤如下:
1. 自定义序列化器
序列化时将name作为外层键,properties作为对应的值,创建ExampleSerializer:
public class ExampleSerializer extends StdSerializer<Example> { protected ExampleSerializer() { super(Example.class); } @Override public void serialize(Example value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeStartObject(); // 把name设为外层键,properties作为对应值写入 gen.writeObjectField(value.getName(), value.getProperties()); gen.writeEndObject(); } }
2. 自定义反序列化器
反序列化时读取外层唯一键作为name,键对应的值解析为properties,创建ExampleDeserializer:
public class ExampleDeserializer extends StdDeserializer<Example> { protected ExampleDeserializer() { super(Example.class); } @Override public Example deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); // 获取外层唯一键作为name属性值 String name = node.fieldNames().next(); JsonNode propertiesNode = node.get(name); // 解析内层键值对到properties Map Map<String, String> properties = new HashMap<>(); propertiesNode.fieldNames().forEachRemaining(key -> { properties.put(key, propertiesNode.get(key).asText()); }); Example example = new Example(name); example.setProperties(properties); return example; } }
3. 为Example类绑定(反)序列化器
在Example类上添加@JsonSerialize和@JsonDeserialize注解,指定自定义的序列化器和反序列化器:
@lombok.Data @JsonSerialize(using = ExampleSerializer.class) @JsonDeserialize(using = ExampleDeserializer.class) public class Example { private String name; private Map<String,String> properties = new HashMap<>(); public Example(String name) { this.name = name; } public void add(String attr1, String val1) { properties.put(attr1, val1); } public static void main(String[] args) throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); // 序列化测试 Example bean = new Example("name1"); bean.add("key1", "value1"); bean.add("key2", "value2"); String result = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(bean); System.out.println("序列化结果:"); System.out.println(result); // 反序列化测试 String json = "{\"name1\":{\"key1\":\"value1\",\"key2\":\"value2\"}}"; Example deserializedBean = mapper.readValue(json, Example.class); System.out.println("\n反序列化结果:"); System.out.println("name: " + deserializedBean.getName()); System.out.println("properties: " + deserializedBean.getProperties()); } }
运行效果
执行main方法后,序列化输出与目标JSON结构一致:
{ "name1" : { "key1" : "value1", "key2" : "value2" } }
反序列化后能正确还原对象属性:
反序列化结果: name: name1 properties: {key1=value1, key2=value2}
内容的提问来源于stack exchange,提问作者János Balázs
相关产品推荐
相关产品推荐

