如何在不自定义ObjectMapper的情况下序列化只读类并忽略null值
解决Jackson局部序列化忽略Null值的问题
你直接在Controller方法上标注@JsonInclude是无效的,这个注解的作用对象是类、字段或构造方法参数,无法直接作用于Controller方法来控制返回对象的序列化规则。以下是两种符合你需求的声明式解决方案:
方案一:使用Jackson Mixin(适配只读类场景)
这是Jackson原生的声明式方案,无需修改目标类的代码:
- 定义一个Mixin抽象类,添加忽略Null值的注解:
@JsonInclude(JsonInclude.Include.NON_NULL) public abstract class SomeObjectMixin { }
- 在目标接口中,创建局部ObjectMapper并注册Mixin,序列化后返回JSON字符串:
@RestController public class SomeObjectController { @GetMapping(value = "/some-object-with-no-nulls", produces = MediaType.APPLICATION_JSON_VALUE) public Mono<String> getSomeObject() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); // 为只读类绑定Mixin规则 objectMapper.addMixIn(SomeObject.class, SomeObjectMixin.class); SomeObject obj = new SomeObject(null, "string"); return Mono.just(objectMapper.writeValueAsString(obj)); } // 只读的SomeObject类(假设无法修改) @NoArgsConstructor @Getter public static class SomeObject { private String firstField; private String secondField; public SomeObject(String firstField, String secondField) { this.firstField = firstField; this.secondField = secondField; } } }
该方案仅对当前接口生效,不会影响其他接口的序列化行为。
方案二:利用ResponseBodyAdvice做局部拦截
如果希望更优雅地复用规则,可以通过Spring的ResponseBodyAdvice实现局部接口的序列化配置:
- 创建拦截类,指定仅对目标接口生效:
@ControllerAdvice public class LocalNonNullSerializationAdvice implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { // 匹配目标方法,可通过方法名、请求路径、自定义注解等方式判断 return "getSomeObject".equals(returnType.getMethod().getName()); } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { if (body instanceof Mono) { return ((Mono<?>) body).map(this::serializeWithNonNullIgnored); } return serializeWithNonNullIgnored(body); } private String serializeWithNonNullIgnored(Object obj) { try { ObjectMapper mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); return mapper.writeValueAsString(obj); } catch (JsonProcessingException e) { throw new RuntimeException("序列化失败", e); } } }
- Controller方法保持原有写法即可:
@GetMapping("/some-object-with-no-nulls") public Mono<SomeObject> getSomeObject() { return Mono.just(new SomeObject(null, "string")); }
内容的提问来源于stack exchange,提问作者Sergey Zolotarev
相关产品推荐
相关产品推荐

