如何基于Type字段值动态设置Jackson序列化的属性名?
动态根据Type字段调整JSON属性名的解决方案
不用创建十多个子类,直接利用Jackson的自定义序列化逻辑就能实现需求,以下是两种实用方案:
方案一:自定义全量序列化器
直接为Data类编写序列化器,手动控制每个字段的输出键名:
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; public class DataSerializer extends JsonSerializer<Data> { @Override public void serialize(Data data, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeStartObject(); // 根据type动态选择surname的JSON键名 String surnameKey = data.getType() == Type.PERSON ? "name" : "username"; gen.writeStringField(surnameKey, data.getSurname()); // 输出type字段 gen.writeStringField("type", data.getType().name()); // 如果有其他字段,在这里按同样方式添加 gen.writeEndObject(); } }
然后在Data类上添加注解指定序列化器:
import com.fasterxml.jackson.databind.annotation.JsonSerialize; @JsonSerialize(using = DataSerializer.class) class Data { @JsonAlias({"username", "name"}) String surname; Type type; // 必须添加getter方法,序列化器需要访问字段值 public String getSurname() { return surname; } public Type getType() { return type; } // 可选:添加setter和构造方法 } enum Type{ PERSON, USER }
方案二:使用BeanSerializerModifier修改单个字段
如果Data类有很多其他字段,不想手动写全量序列化逻辑,可以用BeanSerializerModifier单独修改surname字段的序列化行为:
1. 编写Modifier类
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 DataBeanSerializerModifier extends BeanSerializerModifier { @Override public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) { for (BeanPropertyWriter writer : beanProperties) { if ("surname".equals(writer.getName())) { // 为surname字段指定自定义序列化逻辑 writer.assignSerializer(new JsonSerializer<String>() { @Override public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException { // 获取当前序列化的Data对象 Data currentData = (Data) gen.getCurrentValue(); String targetKey = currentData.getType() == Type.PERSON ? "name" : "username"; gen.writeStringField(targetKey, value); } }); // 移除原有的字段writer,避免重复输出 beanProperties.remove(writer); break; } } return beanProperties; } }
2. 注册到ObjectMapper
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; ObjectMapper mapper = new ObjectMapper(); SimpleModule customModule = new SimpleModule(); customModule.setSerializerModifier(new DataBeanSerializerModifier()); mapper.registerModule(customModule);
方案对比
- 方案一:代码简洁直接,适合字段较少的
Data类,但如果后续新增字段,需要手动在序列化器中添加输出逻辑。 - 方案二:只修改目标字段的行为,保留其他字段的默认序列化逻辑,扩展性更强,适合字段较多的场景。
如果需要反序列化(JSON转Data对象),可以结合@JsonAlias注解,或者编写对应的自定义反序列化器,逻辑和序列化类似,根据JSON中的键名动态赋值给surname字段。
内容的提问来源于stack exchange,提问作者Mohsen
相关产品推荐
相关产品推荐

