如何在不通过ObjectMapper时在JsonParser上设置ObjectCodec?
注意:这是使用Jackson 2.3.2
为了满足我的一个项目的需要,我正在编写一个自定义的JsonParser
,它记录了一个Map
,其中键是JsonPointer
,值是Integer
s(指针指向的行号)。
该类名为LineRecorderJsonParser
。 它由LineRecorderJsonFactory
生成,它是一个简单的委托:
public final class LineRecorderJsonFactory extends JsonFactory { @Override protected JsonParser _createParser(final InputStream in, final IOContext ctxt) throws IOException, JsonParseException { final JsonParser parser = super._createParser(in, ctxt); return new LineRecorderJsonParser(parser); } @Override protected JsonParser _createParser(final Reader r, final IOContext ctxt) throws IOException, JsonParseException { final JsonParser parser = super._createParser(r, ctxt); return new LineRecorderJsonParser(parser); } @Override protected JsonParser _createParser(final byte[] data, final int offset, final int len, final IOContext ctxt) throws IOException, JsonParseException { final JsonParser parser = super._createParser(data, offset, len, ctxt); return new LineRecorderJsonParser(parser); } }
我已使用以下代码测试了代码的工作原理:
public static void main(final String... args) throws IOException { final JsonFactory factory = new LineRecorderJsonFactory(); final ObjectMapper mapper = new ObjectMapper(factory); final Closer closer = Closer.create(); final InputStream in; try { in = closer.register(LineTesting.class.getResourceAsStream ("/testfile.json")); mapper.readTree(in); } finally { closer.close(); } }
但现在我想测试一下; 所以我写了以下测试代码:
public final class LineRecorderJsonParserTest { private static final String INCORRECT_LINE_INFO = "generated line info is incorrect; expected: %s, actual: %s"; private JsonFactory factory; private ObjectMapper mapper; @BeforeMethod public void initFactory() { factory = new LineRecorderJsonFactory(); mapper = new ObjectMapper(); } @DataProvider public Iterator getLineData() { final List list = Lists.newArrayList(); list.add(new Object[] { "1" }); return list.iterator(); } @Test(dataProvider = "getLineData") public void lineNumbersAreCorrectlyReported(final String subdir) throws IOException { final String basePath = "/parser/" + subdir + '/'; final Closer closer = Closer.create(); final TypeReference<Map> typeRef = new TypeReference<Map>() {}; final InputStream input, lines; final Map actual, expected; final LineRecorderJsonParser parser; try { input = closer.register(inputFrom(basePath + "input.json")); lines = closer.register(inputFrom(basePath + "lines.json")); expected = mapper.readValue(lines, typeRef); parser = (LineRecorderJsonParser) factory.createParser(input); //parser.setCodec(factory.getCodec()); // Doesn't change anything... parser.readValueAsTree(); // FAILS HERE actual = parser.getLineInfo(); assertEquals(actual, expected, String.format(INCORRECT_LINE_INFO, expected, actual)); } catch (IOException e) { throw closer.rethrow(e); } finally { closer.close(); } } private static InputStream inputFrom(final String path) { return LineRecorderJsonParserTest.class.getResourceAsStream(path); } }
不幸的是,这不起作用。 我得到以下exception:
java.lang.IllegalStateException: No ObjectCodec defined for the parser, can not deserialize JSON into JsonNode tree at com.fasterxml.jackson.core.JsonParser.readValueAsTree(JsonParser.java:1507) at com.fasterxml.jackson.core.util.JsonParserDelegate.readValueAsTree(JsonParserDelegate.java:371) at com.github.fge.jackson.parse.LineRecorderJsonParserTest.lineNumbersAreCorrectlyReported(LineRecorderJsonParserTest.java:84)
即使我(尝试并且)自己设置了一个ObjectCodec
(参见代码),我也得到了这个例外……
我究竟做错了什么? 我如何测试这个类,因为当你直接使用ObjectMapper
读取时,你没有机会获取底层的解析器?
或者, JsonFactory.setCodec(mapper)
。
好吧,在我提出这个问题后,我发现如何做到这一点甚至几分钟……如果它对其他人有用,我会回答自己。
首先,我的JsonFactory
的.getCodec()
返回null
; 如果您尝试将其提供给null编解码器, JsonParser
不会对您大喊大叫。
其次, ObjectMapper
扩展了ObjectCodec
,而ObjectCodec
有一个读取树的方法 (事实上,它通常包含你在ObjectMapper
上使用的所有方法)。
因此,将代码更改为此工作:
parser = (LineRecorderJsonParser) factory.createParser(input); mapper.readTree(parser); actual = parser.getLineInfo();