使用Jackson JsonGenerator包装JSON列表时遇No ObjectCodec defined异常
解决Jackson JsonGenerator.writeTree()抛出No ObjectCodec defined异常
问题原因
你遇到的IllegalStateException: No ObjectCodec defined是因为创建的JsonGenerator没有绑定ObjectCodec,而writeTree(JsonNode)方法需要通过ObjectCodec完成JsonNode的序列化。直接用JsonFactory创建的JsonGenerator默认没有关联任何ObjectCodec,调用writeTree时就会报错。
另外代码里还有两个需要修正的细节:
- 多余的
jsonGenerator.writeRaw(":");会导致JSON格式错误,writeFieldName后直接调用writeTree会自动生成正确的键值分隔符 - 字段名和期望结构不匹配:代码中
type对应期望的isA,creationDate对应createdOn
修正后的代码
private InputStream generateJsonDocumentWrapper(final InputStream inputEventList) throws IOException { final PipedInputStream jsonDocumentWriter = new PipedInputStream(); final PipedOutputStream out = new PipedOutputStream(jsonDocumentWriter); final ExecutorService executorService = Executors.newWorkStealingPool(); final ObjectMapper objectMapper = new ObjectMapper() .registerModule(new JavaTimeModule()) .enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS); final JsonParser jsonParser = objectMapper.getFactory().createParser(inputEventList); final JsonNode node = jsonParser.readValueAsTree(); executorService.execute(() -> { try (JsonGenerator jsonGenerator = objectMapper.getFactory().createGenerator(out)) { // 给JsonGenerator绑定ObjectCodec,这是解决异常的核心 jsonGenerator.setCodec(objectMapper); jsonGenerator.writeStartObject(); jsonGenerator.writeStringField("isA", "customerDocument"); // 修正字段名 jsonGenerator.writeStringField("createdOn", Instant.now().toString()); // 修正字段名 jsonGenerator.writeFieldName("customerBody"); jsonGenerator.writeStartObject(); jsonGenerator.writeFieldName("customerList"); // 移除多余的writeRaw(":") jsonGenerator.writeTree(node); jsonGenerator.writeEndObject(); jsonGenerator.writeEndObject(); jsonGenerator.flush(); } catch (IOException ex) { ex.printStackTrace(); } finally { executorService.shutdown(); // 记得关闭线程池释放资源 } }); return jsonDocumentWriter; }
更简洁的替代写法
其实可以直接用ObjectMapper构建整个JSON结构,不需要手动操作JsonGenerator,代码更易维护:
private InputStream generateJsonDocumentWrapper(final InputStream inputEventList) throws IOException { final ObjectMapper objectMapper = new ObjectMapper() .registerModule(new JavaTimeModule()) .enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS); final JsonNode customerListNode = objectMapper.readTree(inputEventList); // 构建包装结构的Node ObjectNode rootNode = objectMapper.createObjectNode(); rootNode.put("isA", "customerDocument"); rootNode.put("createdOn", Instant.now().toString()); ObjectNode customerBodyNode = objectMapper.createObjectNode(); customerBodyNode.set("customerList", customerListNode); rootNode.set("customerBody", customerBodyNode); // 将Node转为InputStream返回 ByteArrayOutputStream baos = new ByteArrayOutputStream(); objectMapper.writeValue(baos, rootNode); return new ByteArrayInputStream(baos.toByteArray()); }
这种方式不需要管道流和线程池,避免了多线程带来的潜在问题,可读性和维护性更强。
关键说明
- 调用
JsonGenerator.writeTree()时,必须通过setCodec(ObjectCodec)给生成器绑定有效的ObjectCodec(通常就是你的ObjectMapper实例) - 直接通过
JsonFactory创建的JsonGenerator不会自动关联ObjectCodec,需要手动设置 - 用
ObjectNode构建JSON结构是Jackson的惯用写法,比手动操作JsonGenerator更简洁可靠
内容的提问来源于stack exchange,提问作者BATMAN_2008
相关产品推荐
相关产品推荐

