Jackson序列化/反序列化时如何获取完整JSON字符串?
好问题!在基于REST API的Jackson自定义序列化/反序列化流程里,要从JsonParser、DeserializationContext、SerializationContext拿到完整的JSON字符串确实需要注意一些细节,我来给你逐个场景拆解:
一、反序列化场景(JsonParser + DeserializationContext)
首先说你遇到的情况:直接调用jsonParser.getCurrentLocation().getSourceRef()拿到的是Jersey封装的UnCloseableInputStream,这是因为Jackson默认是流式解析,输入流是单向读取的,而且如果解析已经进行了一部分,流的指针已经移动,直接读只能拿到剩余内容,没法得到完整JSON。
这里有两种可靠的解决方式:
1. 提前缓存输入流
如果能在解析开始前就把整个请求体的流缓存下来,后续就能随时获取完整JSON。比如借助Apache Commons IO工具类读取流内容:
// 先读取完整流内容 InputStream inputStream = (InputStream) jsonParser.getCurrentLocation().getSourceRef(); byte[] jsonBytes = org.apache.commons.io.IOUtils.toByteArray(inputStream); String fullJson = new String(jsonBytes, StandardCharsets.UTF_8); // 注意:读取完流后,需要重新创建一个可重复读取的流给JsonParser继续解析 jsonParser = jsonParser.getCodec().getFactory().createParser(new ByteArrayInputStream(jsonBytes));
提示:如果是在Jersey环境下,也可以通过ReaderInterceptor提前拦截请求体,先缓存再传递给Jackson,避免流只能读一次的问题。
2. 解析为JsonNode再转字符串
利用Jackson的树模型,先把整个JSON解析成JsonNode,再转成字符串,同时重置JsonParser保证后续解析正常:
// 读取整个JSON为JsonNode JsonNode rootNode = jsonParser.readValueAsTree(); String fullJson = rootNode.toString(); // 重置JsonParser到初始状态,确保自定义反序列化后续步骤能正常执行 jsonParser = rootNode.traverse(jsonParser.getCodec());
这种方式不用处理流的细节,比较省心,但会额外做一次解析,适合对性能要求不高的场景。
二、序列化场景(SerializationContext)
SerializationContext本身没有直接获取完整序列化结果的方法,因为Jackson序列化是逐步输出内容的。要拿到完整JSON字符串,需要额外执行一次序列化:
1. 直接用ObjectMapper序列化对象
// 从上下文获取ObjectMapper ObjectMapper mapper = (ObjectMapper) serializationContext.getGenerator().getCodec(); // 序列化对象得到完整JSON字符串 String fullJson = mapper.writeValueAsString(yourSourceObject);
2. 用ByteArrayOutputStream捕获输出
如果你需要更底层的控制,可以手动创建JsonGenerator来生成完整输出:
ByteArrayOutputStream baos = new ByteArrayOutputStream(); JsonGenerator generator = serializationContext.getCodec().getFactory() .createGenerator(baos, JsonEncoding.UTF8); generator.writeObject(yourSourceObject); generator.flush(); String fullJson = baos.toString(StandardCharsets.UTF_8.name());
同样,这种方式也会额外序列化一次,要注意性能开销。
总结
- 反序列化时:优先考虑提前缓存流或者解析为JsonNode,避免直接操作已移动指针的输入流;
- 序列化时:需要额外执行一次序列化操作来获取完整JSON;
- 无论哪种方式,都要注意保证后续的序列化/反序列化流程不受影响(比如重置JsonParser)。
内容的提问来源于stack exchange,提问作者PDS

