如何让同一通用类被不同类引用时配置不同的JsonProperty值
可行解决方案
完全可以实现通用类复用,不需要为每个场景单独定义类,以下是两种Jackson生态下的成熟方案:
方案1:使用Jackson Mixin(混合注解)实现动态字段重命名
- 原理:Mixin可以在不修改原有类代码的前提下,为类动态附加注解配置,不同使用场景绑定不同的Mixin即可实现字段名差异化
- 实现步骤:
首先定义无场景绑定的通用基础类:
// 通用公共类,不写死序列化配置 public class Common { private String s; // 构造器、getter、setter省略 } public class First { @JsonProperty("first") private List<Common> firstCommonList; // 构造器、getter、setter省略 } public class Second { @JsonProperty("second") private List<Common> secondCommonList; // 构造器、getter、setter省略 }
然后为不同场景定义对应的Mixin接口:
// First场景下的Common字段映射规则 public interface CommonFirstMixin { @JsonProperty("firstCommon") String getS(); } // Second场景下的Common字段映射规则 public interface CommonSecondMixin { @JsonProperty("secondCommon") String getS(); }
序列化时为ObjectMapper绑定对应场景的Mixin即可:
// 序列化First类时的配置 ObjectMapper firstMapper = new ObjectMapper(); firstMapper.addMixIn(Common.class, CommonFirstMixin.class); String firstJson = firstMapper.writeValueAsString(firstInstance); // 序列化Second类时的配置 ObjectMapper secondMapper = new ObjectMapper(); secondMapper.addMixIn(Common.class, CommonSecondMixin.class); String secondJson = secondMapper.writeValueAsString(secondInstance);
提示:如果是SpringBoot项目,可以为不同场景注入配置了对应Mixin的
ObjectMapperBean,直接使用即可。
方案2:使用自定义序列化器 + 上下文传递场景标识
如果不想维护多个ObjectMapper实例,可以通过自定义序列化器结合ThreadLocal传递场景标识,实现动态字段名输出:
// 场景标识持有者 public class SceneHolder { private static final ThreadLocal<String> CURRENT_SCENE = new ThreadLocal<>(); public static void setScene(String scene) {CURRENT_SCENE.set(scene);} public static String getScene() {return CURRENT_SCENE.get();} public static void clear() {CURRENT_SCENE.remove();} } // 自定义Common类序列化器 public class CommonSerializer extends StdSerializer<Common> { public CommonSerializer() {super(Common.class);} @Override public void serialize(Common value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeStartObject(); String scene = SceneHolder.getScene(); // 根据场景输出不同的字段名 if ("first".equals(scene)) { gen.writeStringField("firstCommon", value.getS()); } else if ("second".equals(scene)) { gen.writeStringField("secondCommon", value.getS()); } else { gen.writeStringField("defaultField", value.getS()); } gen.writeEndObject(); } }
给Common类加上序列化器注解:
@JsonSerialize(using = CommonSerializer.class) public class Common { private String s; // getter、setter省略 }
使用时提前设置场景即可:
// 序列化First场景 SceneHolder.setScene("first"); String firstJson = new ObjectMapper().writeValueAsString(firstInstance); SceneHolder.clear(); // 序列化Second场景 SceneHolder.setScene("second"); String secondJson = new ObjectMapper().writeValueAsString(secondInstance); SceneHolder.clear();
两种方案各有优劣:Mixin方案无侵入、逻辑清晰,适合场景固定的情况;自定义序列化器更灵活,适合场景多、动态性强的场景,完全不需要为每个场景新增类。
内容的提问来源于stack exchange,提问作者Aunny
相关产品推荐
相关产品推荐

