Skip to content

Commit 74f87e4

Browse files
committed
Fix BlockAwareJsonParser skipChildren level accounting. (#1444)
The BlockAwareJsonParser is used to set a checkpoint on a JSON stream and exit the current blocks that the cursor is in back to the same level of the content that it was created at. If skipChildren is called to skip over an open array or object, the internal level counter will not be updated to account for the array or object that was skipped over. This PR updates the skipChildren method to check the currentToken and conditionally decrement the internal nested level counter if we ended up at an end of an array or object.
1 parent d58dfa2 commit 74f87e4

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

mr/src/main/java/org/elasticsearch/hadoop/serialization/json/BlockAwareJsonParser.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ public Token nextToken() {
105105
@Override
106106
public void skipChildren() {
107107
delegate.skipChildren();
108+
updateLevelBasedOn(delegate.currentToken());
108109
}
109110

110111
@Override

mr/src/test/java/org/elasticsearch/hadoop/serialization/json/BlockAwareJsonParserTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,34 @@ public void testSkippingAndEncounterEOF() {
176176
blockParser.exitBlock();
177177
assertThat(parser.currentToken(), nullValue());
178178
}
179+
180+
/**
181+
* We increment the level of nesting in the parser when getting the next token. If that token starts an array or object,
182+
* the "open" counter is incremented. If we then call `skipChildren` instead of iterating to the end of the object, make
183+
* sure that the open counter is decremented.
184+
*/
185+
@Test
186+
public void testExitBlockAfterSkippingChildren() {
187+
String data = "{\"nested\":{\"array\":[\"test\"],\"scalar\":1}}";
188+
// ^ ! |-------------^
189+
// ! = skipChildren
190+
Parser parser = new JacksonJsonParser(data.getBytes(Charset.defaultCharset()));
191+
assertThat(parser.nextToken(), equalTo(Parser.Token.START_OBJECT));
192+
assertThat(parser.nextToken(), equalTo(Parser.Token.FIELD_NAME));
193+
assertThat(parser.text(), equalTo("nested"));
194+
assertThat(parser.nextToken(), equalTo(Parser.Token.START_OBJECT));
195+
BlockAwareJsonParser blockAwareJsonParser = new BlockAwareJsonParser(parser);
196+
assertThat(blockAwareJsonParser.getLevel(), equalTo(1));
197+
assertThat(blockAwareJsonParser.nextToken(), equalTo(Parser.Token.FIELD_NAME));
198+
assertThat(blockAwareJsonParser.text(), equalTo("array"));
199+
assertThat(blockAwareJsonParser.nextToken(), equalTo(Parser.Token.START_ARRAY));
200+
assertThat(blockAwareJsonParser.getLevel(), equalTo(2));
201+
blockAwareJsonParser.skipChildren();
202+
assertThat(blockAwareJsonParser.currentToken(), equalTo(Parser.Token.END_ARRAY));
203+
assertThat(blockAwareJsonParser.getLevel(), equalTo(1));
204+
blockAwareJsonParser.exitBlock();
205+
assertThat(parser.currentToken(), equalTo(Parser.Token.END_OBJECT));
206+
assertThat(parser.nextToken(), equalTo(Parser.Token.END_OBJECT));
207+
assertThat(parser.nextToken(), nullValue());
208+
}
179209
}

0 commit comments

Comments
 (0)