Jackson 1.9序列化JSON时如何按条件动态移除指定属性
Jackson 1.9 动态排除序列化字段方案
针对你用Jackson 1.9.13、需要单次序列化时排除instructorId字段、又不能修改原POJO影响其他场景的需求,最优解是用Jackson原生的动态属性过滤能力,完全不需要正则替换JSON、反序列化转Map这类笨重又容易出问题的方案。
具体实现
核心思路是给本次序列化操作单独配置属性过滤规则,规则只在当前序列化逻辑生效,不会修改全局ObjectMapper配置,也不需要改动CourseRequest类的代码:
OAuthRequest request = new OAuthRequest(...); CourseRequest courseRequest = new CourseRequest(...); ObjectMapper mapper = new ObjectMapper(); String courseJson = null; try { // 定义过滤规则:序列化时排除指定的instructorId字段 SimpleFilterProvider filterProvider = new SimpleFilterProvider(); SimpleBeanPropertyFilter fieldFilter = SimpleBeanPropertyFilter.serializeAllExcept("instructorId"); filterProvider.addFilter("dynamicFieldFilter", fieldFilter); // 包装过滤器,不需要给原CourseRequest类加@JsonFilter注解即可生效 FilterProvider dynamicFilter = new FilterProvider() { @Override public BeanPropertyFilter findFilter(Object filterId) { return filterProvider.findFilter("dynamicFieldFilter"); } }; // 仅本次序列化使用过滤配置,完全不影响其他地方的序列化逻辑 courseJson = mapper.writer(dynamicFilter).writeValueAsString(courseRequest); request.addPayload(courseJson); request.send(); } catch (JsonGenerationException e) { logger.error(e); } catch (JsonMappingException e) { logger.error(e); } catch (IOException e) { logger.error(e); }
方案优点
- 零侵入:不需要修改
CourseRequest类的任何代码、不需要加注解,完全不影响项目其他位置对这个POJO的序列化使用 - 性能好:直接在序列化阶段就跳过指定字段,不需要生成完整JSON后再做字符串处理、也不需要二次反序列化为Map操作,没有额外性能损耗
- 灵活性高:如果需要根据业务条件判断是否要排除字段,只需要在定义
fieldFilter的时候加分支逻辑即可——比如满足特定条件时用serializeAllExcept("instructorId"),不满足条件时用SimpleBeanPropertyFilter.serializeAll()保留全部字段,适配多场景需求。
复杂场景备选方案
如果后续你需要更细粒度的序列化控制(比如根据字段值、请求上下文判断是否输出某个字段),可以自定义单次序列化使用的序列化器,同样不会影响全局逻辑:
// 自定义针对当前场景的CourseRequest序列化器 public class CourseRequestPayloadSerializer extends JsonSerializer<CourseRequest> { @Override public void serialize(CourseRequest value, JsonGenerator jgen, SerializerProvider provider) throws IOException { jgen.writeStartObject(); // 只写入需要输出的字段,跳过instructorId jgen.writeNumberField("courseId", value.getCourseId()); jgen.writeStringField("courseName", value.getCourseName()); jgen.writeObjectField("schedule", value.getSchedule()); // 其余需要保留的字段按同样方式写入即可 jgen.writeEndObject(); } } // 调用时仅本次序列化绑定自定义序列化器 courseJson = mapper.writer() .withType(CourseRequest.class) .withSerializer(new CourseRequestPayloadSerializer()) .writeValueAsString(courseRequest);
这个方案的缺点是如果CourseRequest字段较多,手写序列化逻辑比较繁琐,固定排除单个字段的场景优先用前面的属性过滤方案即可。
额外提醒:不要用正则替换JSON字符串的方案,JSON存在嵌套结构、转义字符、字段值和字段名重名等大量边界场景,正则匹配很容易出现误替换、结构损坏的问题,生产环境用有很大隐患。
内容的提问来源于stack exchange,提问作者user2526586
相关产品推荐
相关产品推荐

