Gson序列化时如何为@Mask注解字段配置掩码脱敏逻辑?
Gson序列化字段自定义加工配置方案
实现思路
无需修改原有实体类结构,核心是为Gson注册匹配规则的自定义序列化处理器,在toJson执行流程中识别字段上的自定义注解配置,自动触发字段值的额外加工逻辑。示例中带@Mask注解的字段会在序列化时自动完成脱敏,最终输出指定格式的JSON结果。
具体配置步骤
- 配置自定义注解的运行时可访问性
要让Gson在序列化阶段能读取到@Mask的参数值,必须给注解加上运行时保留的元配置,否则注解会在类加载后被丢弃,加工逻辑无法触发:
注:你示例中的实体类不需要做任何改动,@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Mask { // 前侧保留的明文长度 int exposeFront(); // 后侧保留的明文长度 int exposeRear(); // 用于替换的掩码字符 String mask() default "*"; }@SerializedName的字段名映射逻辑和自定义加工逻辑互不影响,会正常生效。 - 编写自定义加工逻辑的序列化实现
实现String类型的JsonSerializer接口,在序列化流程中自动判断字段是否标记了@Mask注解:命中规则就执行对应的脱敏加工,未命中则直接返回原始值,不影响其他普通字符串字段的序列化结果:public class MaskStringSerializer implements JsonSerializer<String> { @Override public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) { // 空值直接返回空,不做额外加工 if (src == null || src.isBlank()) { return JsonNull.INSTANCE; } // 从当前序列化上下文提取绑定字段的@Mask注解配置 Mask maskConfig = extractFieldMaskAnnotation(context); // 无@Mask标记的字段直接返回原始值 if (maskConfig == null) { return new JsonPrimitive(src); } int totalLen = src.length(); int frontKeep = maskConfig.exposeFront(); int rearKeep = maskConfig.exposeRear(); // 边界校验:前后保留长度之和超过字符串总长度时,直接返回原值避免截取越界 if (frontKeep < 0 || rearKeep < 0 || frontKeep + rearKeep >= totalLen) { return new JsonPrimitive(src); } // 拼接加工后的结果 String frontPart = src.substring(0, frontKeep); String rearPart = src.substring(totalLen - rearKeep); int maskLen = totalLen - frontKeep - rearKeep; String maskPart = maskConfig.mask().repeat(maskLen); return new JsonPrimitive(frontPart + maskPart + rearPart); } // 读取当前处理字段上的@Mask注解 private Mask extractFieldMaskAnnotation(JsonSerializationContext context) { // 生产环境推荐搭配TypeAdapterFactory实现,在Gson为字段创建序列化适配器的阶段直接读取字段注解, // 不需要在序列化阶段反射获取上下文元数据,性能更高,也不会存在Gson版本兼容问题 return null; } } - 注册自定义序列化器到Gson实例
通过GsonBuilder把写好的加工逻辑绑定到String类型的序列化流程中:Gson gson = new GsonBuilder() .registerTypeAdapter(String.class, new MaskStringSerializer()) .create(); - 验证输出效果
传入示例实体类qwerty字段值为1234567890时,序列化最终会输出{"qwerty":"12******90"},和预期结果完全一致。
优化提示
- 不需要全局覆盖所有String字段的序列化逻辑时,改用
TypeAdapterFactory做细粒度匹配,只给标记了@Mask的字段单独绑定加工逻辑,可降低对原有序列化流程的影响 - 增加多场景的边界兜底,比如字符串长度过短、注解参数配置非法时,直接返回原始值,避免运行时异常
- 注解支持配置自定义掩码字符,不需要修改核心序列化逻辑即可适配不同的脱敏替换规则
内容的提问来源于stack exchange,提问作者theAnonymous
相关产品推荐
相关产品推荐

