Jackson序列化引用:Owner序列化时仅展示Hotel部分信息的方案
嘿,这个需求我在项目里碰到过好几次,Jackson其实提供了好几种替代自定义序列化器的方案,我给你梳理几个实用的:
1. 用
@JsonView做视图分层(最推荐的原生方案) 这是Jackson专门为“不同场景展示不同字段”设计的功能,非常灵活。步骤很清晰:
- 先定义两个视图接口,一个对应Hotel的基础信息,一个对应完整信息(注意可以继承,减少重复标注)
- 在Hotel类的字段上标记对应的视图,基础字段标基础视图,额外的完整字段标完整视图
- 在Owner类的Hotel属性上指定用基础视图,这样序列化Owner时只会带出Hotel的基础字段;单独序列化Hotel时,指定用完整视图就能输出全部内容
举个代码例子:
// 定义视图接口,Full继承Basic,这样Full视图会包含Basic的所有字段 public interface BasicHotelView {} public interface FullHotelView extends BasicHotelView {} // Hotel实体类 public class Hotel { @JsonView(BasicHotelView.class) private Long id; @JsonView(BasicHotelView.class) private String name; @JsonView(FullHotelView.class) private String address; @JsonView(FullHotelView.class) private Integer roomCount; // getter、setter省略 } // Owner实体类 public class Owner { private Long id; private String name; // 关联Hotel时只用基础视图 @JsonView(BasicHotelView.class) private Hotel hotel; // getter、setter省略 } // 序列化示例 ObjectMapper mapper = new ObjectMapper(); // 序列化Owner,Hotel只显示id和name String ownerJson = mapper.writeValueAsString(owner); // 单独序列化Hotel,显示所有字段 String hotelJson = mapper.writerWithView(FullHotelView.class).writeValueAsString(hotel);
2. 用
@JsonIgnoreProperties快速排除字段(适合简单场景) 如果只是需要排除Hotel里的几个固定字段,直接在Owner的Hotel属性上用@JsonIgnoreProperties指定要忽略的字段就行,不用写额外的逻辑:
public class Owner { private Long id; private String name; // 序列化时忽略Hotel的address和roomCount字段 @JsonIgnoreProperties({"address", "roomCount"}) private Hotel hotel; // getter、setter省略 }
这个方式的优点是简单直接,缺点是不够灵活——如果后续要调整展示字段,得修改注解,适合字段少且固定的场景。
3. 用DTO(数据传输对象)解耦实体与展示(项目常用方案)
实际项目中很多人会选这种方式,就是为Owner创建一个专门的DTO类,只保留需要展示的字段,包括Hotel的基础信息子集。序列化的时候先把实体转成DTO再输出:
// Owner的响应DTO public class OwnerResponseDTO { private Long id; private String name; private HotelBasicDTO hotel; // 从Owner实体转换的构造方法 public OwnerResponseDTO(Owner owner) { this.id = owner.getId(); this.name = owner.getName(); this.hotel = new HotelBasicDTO(owner.getHotel()); } // 只包含Hotel基础信息的内部DTO public static class HotelBasicDTO { private Long id; private String name; public HotelBasicDTO(Hotel hotel) { this.id = hotel.getId(); this.name = hotel.getName(); } // getter省略 } } // 序列化时 ObjectMapper mapper = new ObjectMapper(); String ownerJson = mapper.writeValueAsString(new OwnerResponseDTO(owner));
这种方式的好处是完全解耦了业务实体和展示层,后续修改展示需求只需要改DTO,不会影响实体类的逻辑,适合复杂的展示场景。
4. 用
@JsonFilter动态控制字段(适合动态场景) 如果需要根据不同的请求动态调整Hotel展示的字段,可以用Jackson的过滤器功能:
- 在Hotel类上标记
@JsonFilter指定过滤器名称 - 序列化Owner时,给ObjectMapper添加过滤器,指定要保留的Hotel字段;单独序列化Hotel时不用过滤器,就会输出全部内容
代码示例:
// 给Hotel标记过滤器 @JsonFilter("hotelFilter") public class Hotel { private Long id; private String name; private String address; private Integer roomCount; // getter、setter省略 } public class Owner { private Long id; private String name; private Hotel hotel; // getter、setter省略 } // 序列化Owner时 ObjectMapper mapper = new ObjectMapper(); FilterProvider filterProvider = new SimpleFilterProvider() // 指定保留id和name字段,其他都过滤掉 .addFilter("hotelFilter", SimpleBeanPropertyFilter.filterOutAllExcept("id", "name")); String ownerJson = mapper.writer(filterProvider).writeValueAsString(owner); // 单独序列化Hotel时,直接用默认mapper即可 String hotelJson = mapper.writeValueAsString(hotel);
这个方式非常灵活,可以根据业务逻辑动态调整要展示的字段,适合需要动态适配不同场景的需求。
内容的提问来源于stack exchange,提问作者JasminDan
相关产品推荐
相关产品推荐

