diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 876a981e9d..1f90f79119 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -2594,7 +2594,14 @@ public JsonNode readTree(String content) throws IOException { public JsonNode readTree(byte[] content) throws IOException { return _readTreeAndClose(_jsonFactory.createParser(content)); } - + + /** + * @since 2.10 + */ + public JsonNode readTree(byte[] content, int offset, int len) throws IOException { + return _readTreeAndClose(_jsonFactory.createParser(content, offset, len)); + } + /** * Method to deserialize JSON content as tree expressed using set of {@link JsonNode} instances. * Returns root of the resulting tree (where root can consist of just a single node if the current diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java index fbea78fc36..3fc4a57866 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectReader.java @@ -1307,6 +1307,12 @@ public T readValue(DataInput src) throws IOException return (T) _bindAndClose(_considerFilter(_parserFactory.createParser(src), false)); } + /* + /********************************************************** + /* Deserialization methods; JsonNode ("tree") + /********************************************************** + */ + /** * Method that reads content from given input source, * using configuration of this reader, and binds it as JSON Tree. @@ -1358,6 +1364,28 @@ public JsonNode readTree(String json) throws IOException return _bindAndCloseAsTree(_considerFilter(_parserFactory.createParser(json), false)); } + /** + * @since 2.10 + */ + public JsonNode readTree(byte[] json) throws IOException + { + if (_dataFormatReaders != null) { + _reportUndetectableSource(json); + } + return _bindAndCloseAsTree(_considerFilter(_parserFactory.createParser(json), false)); + } + + /** + * @since 2.10 + */ + public JsonNode readTree(byte[] json, int offset, int len) throws IOException + { + if (_dataFormatReaders != null) { + _reportUndetectableSource(json); + } + return _bindAndCloseAsTree(_considerFilter(_parserFactory.createParser(json, offset, len), false)); + } + public JsonNode readTree(DataInput src) throws IOException { if (_dataFormatReaders != null) { diff --git a/src/test/java/com/fasterxml/jackson/databind/node/EmptyContentAsTreeTest.java b/src/test/java/com/fasterxml/jackson/databind/node/EmptyContentAsTreeTest.java index cd1694a354..9e4a634f99 100644 --- a/src/test/java/com/fasterxml/jackson/databind/node/EmptyContentAsTreeTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/node/EmptyContentAsTreeTest.java @@ -2,7 +2,10 @@ import java.io.ByteArrayInputStream; import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.TreeNode; import com.fasterxml.jackson.databind.*; /** @@ -12,35 +15,127 @@ public class EmptyContentAsTreeTest extends BaseMapTest { private final ObjectMapper MAPPER = objectMapper(); + private final String EMPTY0 = ""; + private final byte[] EMPTY0_BYTES = EMPTY0.getBytes(StandardCharsets.UTF_8); + private final String EMPTY1 = " \n\t "; + private final byte[] EMPTY1_BYTES = EMPTY1.getBytes(StandardCharsets.UTF_8); + // [databind#1406]: when passing `JsonParser`, indicate lack of content // by returning `null` - public void testNullFromEOFWithParser() throws Exception + public void testNullFromEOFWithParserAndMapper() throws Exception { - assertNull(MAPPER.readTree(new StringReader(""))); - assertNull(MAPPER.readTree(new ByteArrayInputStream(new byte[0]))); + try (JsonParser p = MAPPER.getFactory().createParser(EMPTY0)) { + _assertNullTree(MAPPER.readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(EMPTY1)) { + _assertNullTree(MAPPER.readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(new StringReader(EMPTY0))) { + _assertNullTree(MAPPER.readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(new StringReader(EMPTY1))) { + _assertNullTree(MAPPER.readTree(p)); + } + + try (JsonParser p = MAPPER.getFactory().createParser(EMPTY0_BYTES)) { + _assertNullTree(MAPPER.readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(EMPTY1_BYTES)) { + _assertNullTree(MAPPER.readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(EMPTY1_BYTES, 0, EMPTY1_BYTES.length)) { + _assertNullTree(MAPPER.readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(new ByteArrayInputStream(EMPTY0_BYTES))) { + _assertNullTree(MAPPER.readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(new ByteArrayInputStream(EMPTY1_BYTES))) { + _assertNullTree(MAPPER.readTree(p)); + } } // [databind#1406] - public void testNullFromEOFWithParserViaReader() throws Exception + public void testNullFromEOFWithParserAndReader() throws Exception { - assertNull(MAPPER.readTree(new StringReader(""))); - assertNull(MAPPER.readTree(new ByteArrayInputStream(new byte[0]))); - assertNull(MAPPER.readerFor(JsonNode.class) - .readTree(new StringReader(""))); - assertNull(MAPPER.readerFor(JsonNode.class) - .readTree(new ByteArrayInputStream(new byte[0]))); + try (JsonParser p = MAPPER.getFactory().createParser(EMPTY0)) { + _assertNullTree(MAPPER.reader().readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(EMPTY1)) { + _assertNullTree(MAPPER.reader().readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(new StringReader(EMPTY0))) { + _assertNullTree(MAPPER.reader().readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(new StringReader(EMPTY1))) { + _assertNullTree(MAPPER.reader().readTree(p)); + } + + try (JsonParser p = MAPPER.getFactory().createParser(EMPTY0_BYTES)) { + _assertNullTree(MAPPER.reader().readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(EMPTY1_BYTES)) { + _assertNullTree(MAPPER.reader().readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(EMPTY1_BYTES, 0, EMPTY1_BYTES.length)) { + _assertNullTree(MAPPER.reader().readTree(p)); + } + + try (JsonParser p = MAPPER.getFactory().createParser(new ByteArrayInputStream(EMPTY0_BYTES))) { + _assertNullTree(MAPPER.reader().readTree(p)); + } + try (JsonParser p = MAPPER.getFactory().createParser(new ByteArrayInputStream(EMPTY1_BYTES))) { + _assertNullTree(MAPPER.reader().readTree(p)); + } } // [databind#2211]: when passing content sources OTHER than `JsonParser`, // return "missing node" instead of alternate (return `null`, throw exception). - public void testMissingNodeForEOFOther() throws Exception + public void testMissingNodeForEOFOtherMapper() throws Exception { + _assertMissing(MAPPER.readTree(EMPTY0)); + _assertMissing(MAPPER.readTree(EMPTY1)); + _assertMissing(MAPPER.readTree(new StringReader(EMPTY0))); + _assertMissing(MAPPER.readTree(new StringReader(EMPTY1))); + _assertMissing(MAPPER.readTree(EMPTY0_BYTES)); + _assertMissing(MAPPER.readTree(EMPTY0_BYTES, 0, EMPTY0_BYTES.length)); + _assertMissing(MAPPER.readTree(new ByteArrayInputStream(EMPTY0_BYTES))); + _assertMissing(MAPPER.readTree(EMPTY1_BYTES)); + _assertMissing(MAPPER.readTree(EMPTY1_BYTES, 0, EMPTY1_BYTES.length)); + _assertMissing(MAPPER.readTree(new ByteArrayInputStream(EMPTY1_BYTES))); + + // Assume File, URL, etc are fine. Note: `DataInput` probably can't be made to + // work since it can not easily/gracefully handle unexpected end-of-input } - public void testMissingNodeForEOFOtherViaReader() throws Exception + public void testMissingNodeViaObjectReader() throws Exception { + _assertMissing(MAPPER.reader().readTree(EMPTY0)); + _assertMissing(MAPPER.reader().readTree(EMPTY1)); + _assertMissing(MAPPER.reader().readTree(new StringReader(EMPTY0))); + _assertMissing(MAPPER.reader().readTree(new StringReader(EMPTY1))); + _assertMissing(MAPPER.reader().readTree(EMPTY0_BYTES)); + _assertMissing(MAPPER.reader().readTree(EMPTY0_BYTES, 0, EMPTY0_BYTES.length)); + _assertMissing(MAPPER.reader().readTree(new ByteArrayInputStream(EMPTY0_BYTES))); + _assertMissing(MAPPER.reader().readTree(EMPTY1_BYTES)); + _assertMissing(MAPPER.reader().readTree(EMPTY1_BYTES, 0, EMPTY1_BYTES.length)); + _assertMissing(MAPPER.reader().readTree(new ByteArrayInputStream(EMPTY1_BYTES))); + } + + private void _assertNullTree(TreeNode n) { + if (n != null) { + fail("Should get `null` for reads with `JsonParser`, instead got: "+n.getClass().getName()); + } + } + + private void _assertMissing(JsonNode n) { + /* + assertNotNull("Should not get `null` but `MissingNode`", n); + if (!n.isMissingNode()) { + fail("Should get `MissingNode` but got: "+n.getClass().getName()); + } + */ } }