Java Fastjson动态序列化字段名实战
在使用Java进行开发时,经常需要对接多个外部系统或第三方接口,这些系统对JSON请求/响应中的字段命名标准(如大小写、下划线风格等)往往不一致。传统的序列化策略通常固定输出类属性名,缺乏灵活性。本文将介绍一种基于Fastjson的`NameFilter`结合自定义注解的动态重命名方案,使序列化结果能够根据传入的配置ID动态映射为所需的字段名。
准备条件
本方案依赖以下基础:
1. Java运行环境。
2. com.alibaba.fastjson:fastjson库(建议引入最新版以增强稳定性)。
核心逻辑说明
要实现动态改名,核心思路是利用Fastjson提供的扩展点——NameFilter。该接口会在序列化过程中拦截每个字段的处理。
我们将定义一套自定义注解体系:
- @MyParamName:标记字段,包含默认的别名以及一组不同场景下的别名映射表。
在序列化时,过滤器通过反射读取字段的注解,匹配传入的“场景ID”,返回对应的字段名。
第1步:定义场景标识注解 NameEle
用于存储具体的别名映射关系,通过id区分不同的系统需求,value为实际输出的JSON键名。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface NameEle {
String id(); // 唯一标识,例如 "jl" 代表某特定系统的配置
String value(); // 序列化后显示的字段名,例如 "_id"
}
第2步:定义主控制注解 MyParamName
该注解标注在实体类的Field上,允许配置默认值及多个场景映射数组。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface MyParamName {
String value() default ""; // 默认序列化名称
NameEle[] names() default {}; // 所有可支持的别名映射
}
第3步:实现 NameFilter 过滤器 MyNameFilter
继承NameFilter接口,构造函数接收一个唯一的id参数。过滤过程通过反射匹配注解中的nameEles数组。
import com.alibaba.fastjson.serializer.NameFilter;
import java.lang.reflect.Field;
public class MyNameFilter implements NameFilter {
private String id;
public MyNameFilter(String id) {
this.id = id;
}
@Override
public String process(Object object, String name, Object value) {
try {
Field field = object.getClass().getDeclaredField(name);
// 获取我们定义的自定义注解
MyParamName myParamName = field.getDeclaredAnnotation(MyParamName.class);
// 如果没加注解,保持原字段名
if (myParamName == null) {
return name;
}
NameEle[] nameEles = myParamName.names();
String defaultName = myParamName.value();
// 优先使用默认值
if (nameEles.length == 0 && defaultName != null && !defaultName.isEmpty()) {
return defaultName;
}
// 遍历找到匹配的 ID 并返回对应名称
for (NameEle n : nameEles) {
if (id.equals(n.id())) {
return n.value();
}
}
} catch (Exception e) {
// 发生异常时容错返回原始字段名
}
return name;
}
}
第4步:在实体类中使用注解
以人员信息为例,演示如何配置不同的字段名。
public class Person {
// 针对 id=ln 的场景,输出 "i_d";针对 id=jl 的场景,输出 "_id"
@MyParamName(names = {
@NameEle(id = "ln", value = "i_d"),
@NameEle(id = "jl", value = "_id")
})
private String id;
// 指定固定默认为 "NAME",忽略其他别名
@MyParamName("NAME")
private String name;
private String age; // 无注解,保持原始字段名
// Getters and Setters...
// toString()...
}
第5步:测试验证调用效果
在主方法中实例化对象,并使用不同的过滤器配置进行序列化,观察输出差异。
// 假设此处有一个 main 方法上下文
public static void main(String[] args) {
Person person = new Person();
person.setAge("18");
person.setId("001");
person.setName("张三");
// 场景1:使用 "jl" ID,预期字段名为 _id
String s = JSON.toJSONString(person, new MyNameFilter("jl"));
System.out.println(s);
// 输出示例:{"age":"18","_id":"001","NAME":"张三"}
// 场景2:使用 "ln" ID,预期字段名为 i_d
String s1 = JSON.toJSONString(person, new MyNameFilter("ln"));
System.out.println(s1);
// 输出示例:{"age":"18","i_d":"001","NAME":"张三"}
}
注意事项与排查
- 性能开销:由于涉及反射读取
DeclaredAnnotation,高频调用的场景建议在初始化过滤器前预加载缓存或直接使用硬编码策略,或在JVM参数中开启相关优化选项。 - 兼容性问题:如果在泛型集合序列化(如
List<Person>)时使用该过滤器,需确认fastjson版本是否支持在深层嵌套对象中正确传递上下文ID。如有需要,可能需结合SerializerFeature共同使用。
总结
通过NameFilter配合自定义注解,可以优雅地在Java层实现JSON序列化的动态适配,避免了为了对接不同系统而频繁创建冗余DTO对象的麻烦。以上就是利用Fastjson动态改变JSON序列化属性名的详细内容,更多关于Java高效序列化与反序列化的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









