问题描述:

Note: this is using Jackson 2.3.2

For the needs of one of my projects, I am writing a custom JsonParser which records a Map where keys are JsonPointers and values are Integers (line numbers where the pointer points to).

The class is named LineRecorderJsonParser. It is produced by a LineRecorderJsonFactory which is a simple delegate:

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);

}

}

I have tested that the code works using the following code:

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();

}

}

But now I want to test it; so I wrote the following test code:

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<Object[]> getLineData()

{

final List<Object[]> 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<JsonPointer, Integer>> typeRef

= new TypeReference<Map<JsonPointer, Integer>>() {};

final InputStream input, lines;

final Map<JsonPointer, Integer> 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);

}

}

Unfortunately this doesn't work. I get the following 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)

Even when I (try and) set an ObjectCodec myself (see code), I get this exception...

What am I doing wrong? How can I test this class, since when you read using an ObjectMapper directly, you don't get a chance to grab the underlying parser?

网友答案:

Or, JsonFactory.setCodec(mapper).

网友答案:

Well, I found out how to do that not even minutes after I asked the question... I'll answer to self should it prove useful for other people.

First of all, my JsonFactory's .getCodec() returned null; and JsonParser doesn't yell at you if you try and feed it a null codec.

Second, ObjectMapper extends ObjectCodec, and ObjectCodec has a method to read a tree (it has, in fact, all methods you customarily use on an ObjectMapper).

Therefore, changing the code to this worked:

parser = (LineRecorderJsonParser) factory.createParser(input);
mapper.readTree(parser);
actual = parser.getLineInfo();
相关阅读:
Top