如何让ObjectMapper将含内部Map的Bean序列化为Map形式?
问题描述
我有一个内部使用Map的Bean类:
class MyBean { private Map<String,String> map; public MyBean(String key, String value) { map = Collections.singletonMap(key, value); } }
我希望将其序列化后直接以底层Map作为表现形式,即{"akey":"avalue"}:
... ObjectMapper mapper = new ObjectMapper(); mapper.writeValueAsString(new MyBean("akey", "avalue"));
但默认序列化结果会包含map属性:
{"map":{"akey":"avalue"}}
我已实现一个使用map属性的自定义序列化器,请问这是实现该需求的唯一方式吗?
自定义序列化器代码:
private static class MyBeanSerializer extends StdSerializer<MyBean> { public MyBeanSerializer() { this(null); } public MyBeanSerializer(Class<MyBean> t) { super(t); } @Override public void serialize(MyBean value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeObject(value.map); } }
解决方案
当然不是唯一方式,有更简洁的实现方法:
方法1:使用@JsonValue注解
直接在返回内部Map的方法上添加@JsonValue注解,Jackson会自动将该方法的返回值作为整个对象的序列化结果,无需自定义序列化器:
class MyBean { private Map<String,String> map; public MyBean(String key, String value) { map = Collections.singletonMap(key, value); } @JsonValue public Map<String, String> getMap() { return map; } }
这样序列化后就会直接得到{"akey":"avalue"}的结果,代码量更少,也更符合Jackson的惯用写法。
方法2:让Bean实现Map接口
如果业务场景允许,可以让MyBean直接实现Map接口,将内部Map的操作委托给它,Jackson会把实现Map接口的对象直接序列化为Map结构:
class MyBean implements Map<String, String> { private Map<String,String> map; public MyBean(String key, String value) { map = Collections.singletonMap(key, value); } // 实现Map接口的所有方法,全部委托给内部的map对象 @Override public int size() { return map.size(); } @Override public boolean isEmpty() { return map.isEmpty(); } @Override public boolean containsKey(Object key) { return map.containsKey(key); } // 其他Map方法同理实现... }
这种方式适合需要让MyBean具备Map行为的场景,但需要实现大量接口方法,相对繁琐。
相比之下,@JsonValue注解是最轻便的替代方案,完全可以替代自定义序列化器实现你的需求。
内容的提问来源于stack exchange,提问作者OscarRyz
相关产品推荐
相关产品推荐

