diff --git a/release-notes/VERSION b/release-notes/VERSION index 0cbf81570c..ef4af70e2e 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -17,6 +17,8 @@ Project: jackson-databind #728: TypeFactory#_fromVariable returns unknownType() even though it has enough information to provide a more specific type (reported by jkochaniak@github) +#733: MappingIterator should move past errors or not return hasNext() == true + (reported by Lorrin N, lorrin@github) - Improvement to handling of custom `ValueInstantiator` for delegating mode; no more NPE if `getDelegateCreator()` returns null diff --git a/src/main/java/com/fasterxml/jackson/databind/MappingIterator.java b/src/main/java/com/fasterxml/jackson/databind/MappingIterator.java index ade5a02df6..c97901562a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/MappingIterator.java +++ b/src/main/java/com/fasterxml/jackson/databind/MappingIterator.java @@ -182,17 +182,22 @@ public T nextValue() throws IOException return _throwNoSuchElement(); } _hasNextChecked = false; - T result; - - if (_updatedValue == null) { - result = _deserializer.deserialize(_parser, _context); - } else{ - _deserializer.deserialize(_parser, _context, _updatedValue); - result = _updatedValue; + + try { + if (_updatedValue == null) { + return _deserializer.deserialize(_parser, _context); + } else{ + _deserializer.deserialize(_parser, _context, _updatedValue); + return _updatedValue; + } + } finally { + /* 24-Mar-2015, tatu: As per [#733], need to mark token consumed no + * matter what, to avoid infinite loop for certain failure cases. + * For 2.6 need to improve further. + */ + // Need to consume the token too + _parser.clearCurrentToken(); } - // Need to consume the token too - _parser.clearCurrentToken(); - return result; } /** diff --git a/src/test/java/com/fasterxml/jackson/databind/seq/ReadRecoveryTest.java b/src/test/java/com/fasterxml/jackson/databind/seq/ReadRecoveryTest.java new file mode 100644 index 0000000000..873b0dc03e --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/seq/ReadRecoveryTest.java @@ -0,0 +1,50 @@ +package com.fasterxml.jackson.databind.seq; + +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.seq.ReadValuesTest.Bean; + +/** + * Tests to verify aspects of error recover for reading using + * iterator. + */ +public class ReadRecoveryTest extends BaseMapTest +{ + static class Bean { + public int a; + + @Override public String toString() { return "{Bean, a="+a+"}"; } + } + + /* + /********************************************************** + /* Unit tests; root-level value sequences via Mapper + /********************************************************** + */ + + private final ObjectMapper MAPPER = new ObjectMapper(); + + public void testRootBeans() throws Exception + { + final String JSON = aposToQuotes("{'a':3} {'b':5}"); + MappingIterator it = MAPPER.reader(Bean.class).readValues(JSON); + // First one should be fine + assertTrue(it.hasNextValue()); + Bean bean = it.nextValue(); + assertEquals(3, bean.a); + // but second one not + try { + bean = it.nextValue(); + fail("Should not have succeeded"); + } catch (JsonMappingException e) { + verifyException(e, "Unrecognized field"); + } + // 24-Mar-2015, tatu: With 2.5, best we can do is to avoid infinite loop; + // also, since the next token is END_OBJECT, will produce empty Object + assertTrue(it.hasNextValue()); + bean = it.nextValue(); + assertEquals(0, bean.a); + // and we should be done now + assertFalse(it.hasNextValue()); + it.close(); + } +}