Java中如何为ArrayList的每个元素应用不同的JsonView?
为列表元素动态应用不同JsonView的解决方案
1. 定义视图标记接口
先创建两个空接口,用来标记不同的序列化视图场景:
public class EmpViews { // 标记包含age字段的视图 public interface WithAge {} // 标记不包含age字段的视图 public interface WithoutAge {} }
2. 给Emp类属性绑定视图
在Emp类的属性上用@JsonView注解,指定每个属性允许被哪些视图序列化:
public class Emp { // 两个视图都能序列化id @JsonView({EmpViews.WithAge.class, EmpViews.WithoutAge.class}) private Long id; // 两个视图都能序列化name @JsonView({EmpViews.WithAge.class, EmpViews.WithoutAge.class}) private String name; // 仅WithAge视图能序列化age @JsonView(EmpViews.WithAge.class) private Integer age; // 构造方法、getter/setter省略 }
3. 自定义序列化器实现动态视图切换
Spring默认的@JsonView只能给整个请求响应指定单一视图,要实现每个元素不同视图,需要自定义序列化逻辑:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import java.io.IOException; public class DynamicEmpSerializer extends JsonSerializer<Emp> { private final JsonMapper mapper = new JsonMapper(); @Override public void serialize(Emp emp, JsonGenerator gen, SerializerProvider serializers) throws IOException { ObjectNode node = mapper.valueToTree(emp); // 这里可自定义判断条件,示例中以id=1作为包含age的标记 if (!emp.getId().equals(1L)) { node.remove("age"); } gen.writeTree(node); } }
4. 在Controller中应用自定义序列化器
有两种方式可以生效:
方式一:全局注册(所有Emp对象都适用)
在配置类中注册序列化器:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; @Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(Emp.class, new DynamicEmpSerializer()); mapper.registerModule(module); return mapper; } }
之后Controller直接返回列表即可:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController public class EmpController { @GetMapping("/emps") public List<Emp> getEmps() { Emp emp1 = new Emp(1L, "张三", 25); Emp emp2 = new Emp(2L, "李四", 30); Emp emp3 = new Emp(3L, "王五", 28); return List.of(emp1, emp2, emp3); } }
方式二:局部使用(仅当前接口生效)
在Controller的返回列表上标注@JsonSerialize指定序列化器:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import java.util.List; @RestController public class EmpController { @GetMapping("/emps") @JsonSerialize(contentUsing = DynamicEmpSerializer.class) public List<Emp> getEmps() { Emp emp1 = new Emp(1L, "张三", 25); Emp emp2 = new Emp(2L, "李四", 30); Emp emp3 = new Emp(3L, "王五", 28); return List.of(emp1, emp2, emp3); } }
5. 可选方案:手动构建响应节点
如果不想自定义序列化器,也可以手动构造每个元素的JSON节点,再组成数组返回:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.util.List; @RestController public class EmpController { private final ObjectMapper objectMapper; public EmpController(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @GetMapping("/emps") public ArrayNode getEmps() { ArrayNode arrayNode = objectMapper.createArrayNode(); Emp emp1 = new Emp(1L, "张三", 25); ObjectNode node1 = objectMapper.valueToTree(emp1); arrayNode.add(node1); Emp emp2 = new Emp(2L, "李四", 30); ObjectNode node2 = objectMapper.valueToTree(emp2); node2.remove("age"); arrayNode.add(node2); Emp emp3 = new Emp(3L, "王五", 28); ObjectNode node3 = objectMapper.valueToTree(emp3); node3.remove("age"); arrayNode.add(node3); return arrayNode; } }
内容的提问来源于stack exchange,提问作者Kundan Kumar
相关产品推荐
相关产品推荐

