Jackson优化:如何仅序列化一次HeavyObject生成多份JSON
优化HeavyObject重复序列化的方案
问题背景
我有如下两个POJO:
public class ResponseA { private HeavyObject object; private AdditionalDataA additionalData; public ResponseA(HeavyObject object, AdditionalDataA additionalData) { this.object = object; this.additionalData = additionalData; } }
public class ResponseB { private HeavyObject object; private AdditionalDataB additionalData; public ResponseB(HeavyObject object, AdditionalDataB additionalData) { this.object = object; this.additionalData = additionalData; } }
还有一个向不同端点发送这些对象的方法:
public void sendResponses( ObjectMapper mapper, HeavyObject object, AdditionalDataA addDataA, AdditionalDataB addDataB) { // 此处object被序列化两次,开销很高! String jsonA = mapper.writeValueAsString(new ResponseA(object, addDataA)); String jsonB = mapper.writeValueAsString(new ResponseB(object, addDataB)); sendResponseA(jsonA); sendResponseB(jsonB); }
有没有办法实现序列化这些响应时,仅对HeavyObject执行一次序列化操作?
可行方案
1. 预序列化HeavyObject为JsonNode,再拼接其他数据
利用Jackson的JsonNode复用已序列化的结构,避免重复序列化HeavyObject:
public void sendResponses( ObjectMapper mapper, HeavyObject object, AdditionalDataA addDataA, AdditionalDataB addDataB) throws JsonProcessingException { // 仅序列化HeavyObject一次 JsonNode heavyObjectNode = mapper.valueToTree(object); // 构建ResponseA的JSON节点 ObjectNode responseANode = mapper.createObjectNode(); responseANode.set("object", heavyObjectNode); responseANode.set("additionalData", mapper.valueToTree(addDataA)); String jsonA = mapper.writeValueAsString(responseANode); // 构建ResponseB的JSON节点 ObjectNode responseBNode = mapper.createObjectNode(); responseBNode.set("object", heavyObjectNode); responseBNode.set("additionalData", mapper.valueToTree(addDataB)); String jsonB = mapper.writeValueAsString(responseBNode); sendResponseA(jsonA); sendResponseB(jsonB); }
这种方式直接复用HeavyObject的JsonNode结构,后续仅做节点拼接,序列化开销大幅降低。
2. 预序列化HeavyObject为字符串,手动拼接JSON
如果不想依赖JsonNode,也可以先把HeavyObject序列化为字符串,再手动拼接成完整的响应JSON:
public void sendResponses( ObjectMapper mapper, HeavyObject object, AdditionalDataA addDataA, AdditionalDataB addDataB) throws JsonProcessingException { String heavyObjectJson = mapper.writeValueAsString(object); String addDataAJson = mapper.writeValueAsString(addDataA); String addDataBJson = mapper.writeValueAsString(addDataB); // 拼接ResponseA的JSON String jsonA = String.format("{\"object\":%s,\"additionalData\":%s}", heavyObjectJson, addDataAJson); // 拼接ResponseB的JSON String jsonB = String.format("{\"object\":%s,\"additionalData\":%s}", heavyObjectJson, addDataBJson); sendResponseA(jsonA); sendResponseB(jsonB); }
注意:Jackson会自动处理对象字段中的特殊字符转义,所以只要单个对象的序列化结果合法,拼接后的JSON也会是合法的。
3. 自定义序列化器(复杂场景适用)
如果需要对序列化流程做更多定制,可以为ResponseA和ResponseB实现自定义序列化器,复用预序列化的HeavyObject内容:
public class ResponseASerializer extends StdSerializer<ResponseA> { private final JsonNode preSerializedHeavyObject; public ResponseASerializer(JsonNode preSerializedHeavyObject) { super(ResponseA.class); this.preSerializedHeavyObject = preSerializedHeavyObject; } @Override public void serialize(ResponseA value, JsonGenerator gen, SerializerProvider provider) throws IOException { gen.writeStartObject(); gen.writeFieldName("object"); // 直接写入预序列化的节点内容 gen.writeTree(preSerializedHeavyObject); gen.writeFieldName("additionalData"); provider.defaultSerializeValue(value.getAdditionalData(), gen); gen.writeEndObject(); } }
使用时先预序列化HeavyObject,再为每个Response类型配置对应的序列化器:
public void sendResponses( ObjectMapper mapper, HeavyObject object, AdditionalDataA addDataA, AdditionalDataB addDataB) throws JsonProcessingException { JsonNode heavyObjectNode = mapper.valueToTree(object); // 配置ResponseA的自定义序列化器 ObjectMapper mapperA = mapper.copy(); SimpleModule moduleA = new SimpleModule(); moduleA.addSerializer(new ResponseASerializer(heavyObjectNode)); mapperA.registerModule(moduleA); String jsonA = mapperA.writeValueAsString(new ResponseA(object, addDataA)); // 同理配置ResponseB的自定义序列化器 ObjectMapper mapperB = mapper.copy(); SimpleModule moduleB = new SimpleModule(); moduleB.addSerializer(new ResponseBSerializer(heavyObjectNode)); mapperB.registerModule(moduleB); String jsonB = mapperB.writeValueAsString(new ResponseB(object, addDataB)); sendResponseA(jsonA); sendResponseB(jsonB); }
这种方式适合有特殊序列化需求的场景,但实现成本比前两种更高。
内容的提问来源于stack exchange,提问作者Matías Santurio
相关产品推荐
相关产品推荐

