Gson:如何仅在特定注解下使用自定义序列化器?
解决方案:基于自定义注解+BeanSerializerModifier实现精准ID序列化
听起来你遇到的场景很典型——既要给特定ID字段做自定义序列化(比如掩码),又不能用@JsonAdapter硬编码到类里,还得避免全局影响其他整数字段。结合Jackson的扩展能力,我推荐用自定义注解+BeanSerializerModifier的方案,完美适配你层级深的复杂模型,而且不需要修改现有类的序列化器注解。
1. 定义标记ID字段的自定义注解
先创建一个注解,用来标记所有需要做掩码处理的ID字段,这样不管层级多深,只要字段带这个注解,就能被识别:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface MaskedId { // 可按需添加参数,比如自定义掩码规则、保留位数等 }
2. 实现自定义ID序列化器
写一个专门处理ID掩码的序列化器,这里以“保留后四位,前缀用****代替”为例,你可以根据实际需求修改逻辑:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import java.io.IOException; public class MaskedIdSerializer extends StdSerializer<Integer> { public MaskedIdSerializer() { super(Integer.class); } @Override public void serialize(Integer id, JsonGenerator gen, SerializerProvider provider) throws IOException { if (id == null) { gen.writeNull(); return; } // 自定义掩码逻辑,示例:保留后四位,前面替换为**** String maskedValue = String.format("****%04d", id % 10000); gen.writeString(maskedValue); // 如果需要输出数字类型而非字符串,改用gen.writeNumber(...)即可 } }
3. 用BeanSerializerModifier拦截带注解的字段
这是核心步骤:通过Modifier遍历所有待序列化的字段,检查是否带有@MaskedId注解,若有则替换为我们的自定义序列化器。不管你的模型层级有多深,只要字段标记了注解,都会被自动处理:
import com.fasterxml.jackson.databind.BeanDescription; import com.fasterxml.jackson.databind.SerializationConfig; import com.fasterxml.jackson.databind.ser.BeanPropertyWriter; import com.fasterxml.jackson.databind.ser.BeanSerializerModifier; import java.util.List; public class MaskedIdSerializerModifier extends BeanSerializerModifier { private final MaskedIdSerializer maskedIdSerializer = new MaskedIdSerializer(); @Override public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) { for (BeanPropertyWriter writer : beanProperties) { // 检查当前字段是否带有@MaskedId注解 if (writer.getAnnotation(MaskedId.class) != null) { // 替换该字段的序列化器 writer.assignSerializer(maskedIdSerializer); } } return beanProperties; } }
4. 注册到ObjectMapper生效
最后把这个Modifier注册到你的ObjectMapper实例中,这样所有通过该ObjectMapper序列化的对象,带@MaskedId注解的ID字段都会自动应用掩码逻辑:
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; public class ObjectMapperConfig { public static ObjectMapper createMaskingObjectMapper() { ObjectMapper objectMapper = new ObjectMapper(); SimpleModule module = new SimpleModule(); // 注册自定义的SerializerModifier module.setSerializerModifier(new MaskedIdSerializerModifier()); objectMapper.registerModule(module); return objectMapper; } }
使用示例
在你的数据模型里,给需要掩码的ID字段加上@MaskedId注解即可,嵌套层级的字段也能生效:
public class User { @MaskedId private Integer userId; private String username; // 嵌套对象中的ID同样会被处理 private Address address; // getter/setter 省略 } public class Address { @MaskedId private Integer addressId; private String street; // getter/setter 省略 }
当你用注册了Modifier的ObjectMapper序列化User对象时,userId和address.addressId都会被掩码处理,其他整数字段则保持默认序列化逻辑。
额外扩展
- 如果需要不同的掩码规则,可以给
@MaskedId注解添加参数(比如maskPattern),然后在序列化器中根据参数调整逻辑。 - 若需要反序列化时将掩码值还原为原ID,可采用类似思路,编写自定义反序列化器和
BeanDeserializerModifier。
内容的提问来源于stack exchange,提问作者Andrea
相关产品推荐
相关产品推荐

