反射序列化时跳过特定@tag字段需三步:先用反射读取@tag注解并缓存隐藏字段名,再通过simplebeanpropertyfilter动态注册过滤器到objectmapper,最后确保r8/proguard保留注解、字段名及jackson类。

反射序列化时如何跳过特定 @Tag 字段
Java 反射本身不识别 @Tag —— 它只是个普通注解,除非你主动读取并做逻辑判断。很多同学直接用 getDeclaredFields() 遍历 + ObjectMapper 序列化,结果 @Tag 完全没生效,字段照常输出。
真正起作用的是序列化框架(比如 Jackson)对注解的支持,但 @Tag 不是 Jackson 原生注解,它不会自动触发忽略逻辑。必须自己桥接反射 + 注解解析 + 序列化定制。
- 先用反射拿到字段,检查是否带
@Tag注解且值为"hidden"或类似标记值 - 再把该字段名传给
SimpleBeanPropertyFilter或@JsonIgnoreProperties动态构造 - 别在运行时反复反射解析——缓存
Class → Set<string></string>字段名列表,否则每次序列化都扫一遍字段,性能掉得明显
Jackson 中动态过滤字段的两种可靠写法
硬编码 @JsonIgnore 不行,因为字段隐藏策略是运行时决定的;用 @JsonInclude(JsonInclude.Include.NON_NULL) 也不够精准,它只看值,不看注解语义。
推荐走 Filter 路线,稳定且可控:
- 用
SimpleBeanPropertyFilter.serializeAllExcept(...)构造白名单外的排除集,传入反射扫描出的@Tag隐藏字段名数组 - 搭配
SimpleFilterProvider注册到ObjectMapper,注意:每个请求用同一个ObjectMapper实例时,filter 必须是线程安全的(SimpleBeanPropertyFilter是无状态的,OK) - 别用
@JsonFilter+ 自定义PropertyFilter类去重写serializeAsField——容易漏掉嵌套对象、泛型类型,调试成本高
示例关键片段:
Set<String> hiddenFields = getHiddenFieldNames(targetClass); // 反射读 @Tag
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.serializeAllExcept(hiddenFields);
mapper.setFilterProvider(new SimpleFilterProvider().addFilter("tagFilter", filter));
混淆字段名后反射还能正确匹配吗
能,但前提是混淆工具(如 R8 / ProGuard)没删掉 @Tag 注解,也没把字段名优化成 a、b 后还让你靠名字去过滤。
常见坑在这里:
- R8 默认会移除未被反射引用的注解,必须保留:
-keepattributes Signature,Annotation,InnerClasses - 字段名混淆后,
field.getName()返回的是混淆后的名(如f123),而你原始@Tag是打在源码字段上的,反射仍能读到——但如果你在配置里写死字段名做排除,就彻底失效了 - 更稳的做法:反射阶段不依赖字段名字符串,而是用
field.getAnnotation(Tag.class)判断,然后通过field.setAccessible(true); field.get(obj)确认是否需要隐藏,再交由自定义序列化器处理
Android 上 R8 混淆 + Jackson 动态过滤的兼容要点
Android 端尤其容易崩在 NoSerializerFoundException 或字段全空——不是逻辑错,是 R8 把 Jackson 内部类或泛型信息剪掉了。
- 必须保留 Jackson 核心类:
-keep class com.fasterxml.jackson.databind.** { *; } - 如果用了
@JsonFilter,还要保留 filter 相关类:-keep class com.fasterxml.jackson.annotation.JsonFilter - 实体类不能被完全内联或删除:加
-keep class your.package.model.** { *; },否则反射找不到字段 - 测试时打开
android.enableR8.fullMode=false先验证逻辑,再切回 fullMode 查兼容问题
动态隐藏这事,核心不在“怎么藏”,而在“藏完还能不能被正确识别和跳过”。反射读注解、Jackson 接管序列化、混淆保留元数据——三者缺一不可,少锁住一环,字段就又露出来了。










