Jackson JSON:同一对象不同逻辑序列化实现方案问询
解决Java对象B序列化时List与Map中A的差异化字段问题
刚好之前碰到过类似的场景,用Jackson序列化框架就能轻松搞定这个需求——让同一个类A在List里序列化所有字段,在Map里只序列化id。下面给你两种实用的实现方案:
方法一:用Jackson的JsonView视图机制(推荐,灵活易扩展)
这种方式通过定义不同的"视图"来标记哪些字段在什么场景下序列化,代码侵入性很低:
1. 先定义两个视图标记接口
就两个空接口,用来区分不同的序列化场景:
// 标记需要序列化A所有字段的场景 public interface FullAView {} // 标记只序列化A的id字段的场景 public interface IdOnlyAView {}
2. 给A类的字段绑定视图
给A的每个字段加上@JsonView注解,指定它属于哪个视图。注意id字段要同时属于两个视图,这样两种场景下都会输出:
public class A { // id字段在两种场景下都要序列化 @JsonView({FullAView.class, IdOnlyAView.class}) private Long id; // 这些字段只在"全字段"场景下序列化 @JsonView(FullAView.class) private String name; @JsonView(FullAView.class) private Integer age; // 常规的getter、setter、构造方法就不写了哈 }
3. 给B类的容器字段指定对应的视图
告诉Jackson,List用全字段视图,Map用仅id视图:
public class B { // List<A> 使用全字段视图 @JsonView(FullAView.class) private List<A> all; // Map<Long, A> 使用仅id视图 @JsonView(IdOnlyAView.class) private Map<Long, A> mapped; // 同样省略getter、setter这些 }
4. 序列化时启用视图
最后序列化B的时候,要显式启用视图机制,不然Jackson不会识别这些注解:
ObjectMapper mapper = new ObjectMapper(); // 用Std视图会包含所有标记了@JsonView的字段,刚好满足两种场景的需求 String json = mapper.writerWithView(JsonView.Std.class) .writeValueAsString(你的B对象实例);
方法二:给Map字段用自定义序列化器(更直接,适合需求固定的场景)
如果不想搞视图这么多步骤,也可以直接给Map里的A写个专属序列化器,只输出id:
1. 写一个只序列化A的id的序列化器
这个类负责处理Map中A的序列化逻辑:
public class AIdOnlySerializer extends StdSerializer<A> { public AIdOnlySerializer() { super(A.class); } @Override public void serialize(A aObj, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeStartObject(); gen.writeNumberField("id", aObj.getId()); // 只写id字段 gen.writeEndObject(); } }
2. 给B的Map字段指定这个序列化器
在mapped字段上加上注解,告诉Jackson用我们写的序列化器处理里面的A对象:
public class B { // List<A> 保持默认序列化,自动输出所有字段 private List<A> all; // Map里的A用自定义序列化器,只输出id @JsonSerialize(contentUsing = AIdOnlySerializer.class) private Map<Long, A> mapped; // getter、setter省略 }
3. 正常序列化就行
这时候直接序列化B对象就ok了,List里的A会输出所有字段,Map里的A只会输出id:
ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(你的B对象实例);
两种方案怎么选?
- 如果以后可能还要加别的序列化场景(比如只序列化name和id),选JsonView方案,扩展性强,改改注解就行。
- 如果需求固定死了就这两种场景,选自定义序列化器,更直接,代码逻辑一眼就能看懂。
放心,这两种方案在实际项目里都用过,没问题的~
内容的提问来源于stack exchange,提问作者CommanderData
相关产品推荐
相关产品推荐

