From 19522fb16bc3160f2e032acb3bef9fcff90bb03a Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 27 Oct 2025 15:53:21 -0700 Subject: [PATCH 1/5] Fixes #114: support STRICT_DUPLICATE_DETECTION --- .../dataformat/xml/deser/FromXmlParser.java | 13 +++- .../dataformat/xml/deser/XmlReadContext.java | 52 ++++++++++++- .../StrictDuplicateDetection114Test.java | 78 +++++++++++++++++++ 3 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 src/test/java/com/fasterxml/jackson/dataformat/xml/deser/StrictDuplicateDetection114Test.java diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/FromXmlParser.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/FromXmlParser.java index 7fb2c00e..fdabfdfe 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/FromXmlParser.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/FromXmlParser.java @@ -296,6 +296,10 @@ public FromXmlParser(IOContext ctxt, int genericParserFeatures, ObjectCodec code _ioContext = ctxt; _objectCodec = codec; _parsingContext = XmlReadContext.createRootContext(-1, -1); + // Enable duplicate detection if STRICT_DUPLICATE_DETECTION feature is enabled + if (isEnabled(JsonParser.Feature.STRICT_DUPLICATE_DETECTION)) { + _parsingContext.withDupDetector(this); + } _xmlTokens = Objects.requireNonNull(xmlTokenStream, "xmlTokenStream cannot be null"); _formatFeatures = xmlTokenStream.getFormatFeatures(); final int firstToken; @@ -526,7 +530,12 @@ public void overrideCurrentName(String name) if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) { ctxt = ctxt.getParent(); } - ctxt.setCurrentName(name); + try { + ctxt.setCurrentName(name); + } catch (JsonProcessingException e) { + // Wrap in unchecked exception since we cannot change signature + throw new UncheckedIOException(e); + } } @Override @@ -1050,7 +1059,7 @@ public String nextTextValue() throws IOException } - private void _updateState(JsonToken t) + private void _updateState(JsonToken t) throws JsonProcessingException { switch (t) { case START_OBJECT: diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java index dc7ae3bb..5f152fa1 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.core.io.CharTypes; import com.fasterxml.jackson.core.io.ContentReference; +import com.fasterxml.jackson.core.json.DupDetector; /** * Extension of {@link JsonStreamContext}, which implements @@ -23,6 +24,14 @@ public final class XmlReadContext protected final XmlReadContext _parent; + /** + * Object used for checking for duplicate field names, if enabled + * (null if not enabled) + * + * @since 2.21 + */ + protected DupDetector _dupDetector; + // // // Location information (minus source reference) protected int _lineNr; @@ -92,6 +101,9 @@ protected final void reset(int type, int lineNr, int colNr) _currentName = null; _currentValue = null; _namesToWrap = null; + if (_dupDetector != null) { + _dupDetector.reset(); + } // _nestingDepth fine as is, same level for reuse } @@ -137,9 +149,13 @@ public final XmlReadContext createChildObjectContext(int lineNr, int colNr) XmlReadContext ctxt = _child; if (ctxt == null) { _child = ctxt = new XmlReadContext(this, TYPE_OBJECT, lineNr, colNr); - return ctxt; + } else { + ctxt.reset(TYPE_OBJECT, lineNr, colNr); + } + // Propagate DupDetector to child if parent has one + if (_dupDetector != null) { + ctxt._dupDetector = _dupDetector.child(); } - ctxt.reset(TYPE_OBJECT, lineNr, colNr); return ctxt; } @@ -186,8 +202,18 @@ public final void valueStarted() { ++_index; } - public void setCurrentName(String name) { + public void setCurrentName(String name) throws JsonProcessingException { _currentName = name; + // Only check for duplicates in Object contexts, not in Arrays or Root + if (_dupDetector != null && _type == TYPE_OBJECT) { + if (_dupDetector.isDup(name)) { + // Use the parser's location for the error message + Object src = (_dupDetector == null) ? null : _dupDetector.getSource(); + throw new JsonParseException(null, + "Duplicate field '" + name + "'", startLocation( + (src instanceof ContentReference) ? (ContentReference) src : ContentReference.unknown())); + } + } } public void setNamesToWrap(Set namesToWrap) { @@ -199,6 +225,26 @@ public boolean shouldWrap(String localName) { return (_namesToWrap != null) && _namesToWrap.contains(localName); } + /** + * Method that can be called to create a new DupDetector for this context, + * if duplicate detection is enabled. + * + * @param parser The parser instance to associate with the detector + * @return The newly created DupDetector + * @since 2.21 + */ + public DupDetector withDupDetector(JsonParser parser) { + _dupDetector = DupDetector.rootDetector(parser); + return _dupDetector; + } + + /** + * @since 2.21 + */ + public DupDetector getDupDetector() { + return _dupDetector; + } + protected void convertToArray() { _type = TYPE_ARRAY; } diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/StrictDuplicateDetection114Test.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/StrictDuplicateDetection114Test.java new file mode 100644 index 00000000..5c77dcc4 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/StrictDuplicateDetection114Test.java @@ -0,0 +1,78 @@ +package com.fasterxml.jackson.dataformat.xml.deser; + +import org.junit.jupiter.api.Test; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.exc.StreamReadException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.json.JsonMapper; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.fasterxml.jackson.dataformat.xml.XmlTestUtil; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Tests for [dataformat-xml#114]: Support for STRICT_DUPLICATE_DETECTION + */ +public class StrictDuplicateDetection114Test extends XmlTestUtil +{ + static class TestBean { + public String field1; + public String field2; + } + + private final XmlMapper XML_MAPPER = XmlMapper.builder() + .enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION) + .build(); + + private final ObjectMapper JSON_MAPPER = JsonMapper.builder() + .enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION) + .build(); + + // [dataformat-xml#114] + @Test + public void testStrictDuplicateDetectionWithPOJO() throws Exception + { + // First verify JSON mapper properly rejects duplicates + final String jsonWithDup = "{\"field1\":\"value1\",\"field1\":\"value2\"}"; + + StreamReadException e = assertThrows(StreamReadException.class, () -> { + JSON_MAPPER.readValue(jsonWithDup, TestBean.class); + }); + assertTrue(e.getMessage().contains("Duplicate field"), + "Expected 'Duplicate field' error, got: " + e.getMessage()); + + // Now test XML mapper should also reject duplicates + final String xmlWithDup = "value1value2"; + + e = assertThrows(StreamReadException.class, () -> { + XML_MAPPER.readValue(xmlWithDup, TestBean.class); + }); + assertTrue(e.getMessage().contains("Duplicate field"), + "Expected 'Duplicate field' error, got: " + e.getMessage()); + } + + @Test + public void testNoDuplicatesShouldWork() throws Exception + { + final String xml = "value1value2"; + + TestBean bean = XML_MAPPER.readValue(xml, TestBean.class); + assertNotNull(bean); + assertEquals("value1", bean.field1); + assertEquals("value2", bean.field2); + } + + @Test + public void testDuplicateDetectionDisabledByDefault() throws Exception + { + XmlMapper mapper = newMapper(); // default mapper without strict duplicate detection + + // Should allow duplicates by default (last value wins) + final String xmlWithDup = "value1value2"; + + TestBean bean = mapper.readValue(xmlWithDup, TestBean.class); + assertNotNull(bean); + assertEquals("value2", bean.field1); // last value wins + } +} From d8841476e041cf8d9fba52252f3c7b3e2a855ef7 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 27 Oct 2025 16:10:50 -0700 Subject: [PATCH 2/5] Minor streamlining --- .../dataformat/xml/deser/FromXmlParser.java | 18 +++--- .../dataformat/xml/deser/XmlReadContext.java | 58 +++++-------------- 2 files changed, 24 insertions(+), 52 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/FromXmlParser.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/FromXmlParser.java index fdabfdfe..70a3236f 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/FromXmlParser.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/FromXmlParser.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.core.exc.StreamConstraintsException; import com.fasterxml.jackson.core.io.IOContext; import com.fasterxml.jackson.core.io.NumberInput; +import com.fasterxml.jackson.core.json.DupDetector; import com.fasterxml.jackson.core.util.ByteArrayBuilder; import com.fasterxml.jackson.core.util.JacksonFeatureSet; @@ -284,22 +285,21 @@ public FromXmlParser(IOContext ctxt, int genericParserFeatures, int xmlFeatures, * This constructor initializes the parser with the given I/O context, parser features, * and object codec for deserializing XML content into Java objects. * - * @since 2.20 * @param ctxt I/O context used for handling low-level I/O operations and buffering * @param genericParserFeatures set of bitmasked parser features to control parsing behavior * @param codec object codec used for converting between JSON-like structures and Java objects * @param xmlTokenStream the pre-processed XML token stream to parse from * @throws IOException if an I/O error occurs during initialization or parsing setup + * + * @since 2.20 */ public FromXmlParser(IOContext ctxt, int genericParserFeatures, ObjectCodec codec, XmlTokenStream xmlTokenStream) throws IOException { super(genericParserFeatures, ctxt.streamReadConstraints()); _ioContext = ctxt; _objectCodec = codec; - _parsingContext = XmlReadContext.createRootContext(-1, -1); - // Enable duplicate detection if STRICT_DUPLICATE_DETECTION feature is enabled - if (isEnabled(JsonParser.Feature.STRICT_DUPLICATE_DETECTION)) { - _parsingContext.withDupDetector(this); - } + DupDetector dups = JsonParser.Feature.STRICT_DUPLICATE_DETECTION.enabledIn(genericParserFeatures) + ? DupDetector.rootDetector(this) : null; + _parsingContext = XmlReadContext.createRootContext(dups, -1, -1); _xmlTokens = Objects.requireNonNull(xmlTokenStream, "xmlTokenStream cannot be null"); _formatFeatures = xmlTokenStream.getFormatFeatures(); final int firstToken; @@ -530,11 +530,11 @@ public void overrideCurrentName(String name) if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) { ctxt = ctxt.getParent(); } + // Unfortunate, but since we did not expose exceptions, need to wrap try { ctxt.setCurrentName(name); - } catch (JsonProcessingException e) { - // Wrap in unchecked exception since we cannot change signature - throw new UncheckedIOException(e); + } catch (IOException e) { + throw new IllegalStateException(e); } } diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java index 5f152fa1..26ec15cc 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java @@ -30,7 +30,7 @@ public final class XmlReadContext * * @since 2.21 */ - protected DupDetector _dupDetector; + protected final DupDetector _dupDetector; // // // Location information (minus source reference) @@ -68,30 +68,22 @@ public final class XmlReadContext */ /** - * @since 2.18 + * @since 2.21 */ - public XmlReadContext(XmlReadContext parent, int nestingDepth, + public XmlReadContext(XmlReadContext parent, DupDetector dups, + int nestingDepth, int type, int lineNr, int colNr) { super(); _type = type; _parent = parent; + _dupDetector = dups; _lineNr = lineNr; _columnNr = colNr; _index = -1; _nestingDepth = nestingDepth; } - /** - * @deprecated Since 2.18 - */ - @Deprecated // since 2.18 - public XmlReadContext(XmlReadContext parent, int type, int lineNr, int colNr) - { - this(parent, (parent == null) ? 0 : parent._nestingDepth + 1, - type, lineNr, colNr); - } - protected final void reset(int type, int lineNr, int colNr) { _type = type; @@ -123,20 +115,22 @@ public void setCurrentValue(Object v) { /********************************************************************** */ - public static XmlReadContext createRootContext(int lineNr, int colNr) { - return new XmlReadContext(null, 0, TYPE_ROOT, lineNr, colNr); + public static XmlReadContext createRootContext(DupDetector dups, int lineNr, int colNr) { + return new XmlReadContext(null, dups, 0, TYPE_ROOT, lineNr, colNr); } public static XmlReadContext createRootContext() { - return new XmlReadContext(null, 0, TYPE_ROOT, 1, 0); + return createRootContext(null, 1, 0); } - + public final XmlReadContext createChildArrayContext(int lineNr, int colNr) { ++_index; // not needed for Object, but does not hurt so no need to check curr type XmlReadContext ctxt = _child; if (ctxt == null) { - _child = ctxt = new XmlReadContext(this, _nestingDepth+1, TYPE_ARRAY, lineNr, colNr); + _child = ctxt = new XmlReadContext(this, + (_dupDetector == null) ? null : _dupDetector.child(), + _nestingDepth+1, TYPE_ARRAY, lineNr, colNr); return ctxt; } ctxt.reset(TYPE_ARRAY, lineNr, colNr); @@ -148,14 +142,12 @@ public final XmlReadContext createChildObjectContext(int lineNr, int colNr) ++_index; // not needed for Object, but does not hurt so no need to check curr type XmlReadContext ctxt = _child; if (ctxt == null) { - _child = ctxt = new XmlReadContext(this, TYPE_OBJECT, lineNr, colNr); + _child = ctxt = new XmlReadContext(this, + (_dupDetector == null) ? null : _dupDetector.child(), + _nestingDepth+1, TYPE_OBJECT, lineNr, colNr); } else { ctxt.reset(TYPE_OBJECT, lineNr, colNr); } - // Propagate DupDetector to child if parent has one - if (_dupDetector != null) { - ctxt._dupDetector = _dupDetector.child(); - } return ctxt; } @@ -225,26 +217,6 @@ public boolean shouldWrap(String localName) { return (_namesToWrap != null) && _namesToWrap.contains(localName); } - /** - * Method that can be called to create a new DupDetector for this context, - * if duplicate detection is enabled. - * - * @param parser The parser instance to associate with the detector - * @return The newly created DupDetector - * @since 2.21 - */ - public DupDetector withDupDetector(JsonParser parser) { - _dupDetector = DupDetector.rootDetector(parser); - return _dupDetector; - } - - /** - * @since 2.21 - */ - public DupDetector getDupDetector() { - return _dupDetector; - } - protected void convertToArray() { _type = TYPE_ARRAY; } From 565c62501029bebbc0dc08db64a33b01dd12df77 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 27 Oct 2025 16:15:15 -0700 Subject: [PATCH 3/5] Yet more tweaking --- .../StrictDuplicateDetection114Test.java | 31 ++++++------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/StrictDuplicateDetection114Test.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/StrictDuplicateDetection114Test.java index 5c77dcc4..259228cd 100644 --- a/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/StrictDuplicateDetection114Test.java +++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/StrictDuplicateDetection114Test.java @@ -4,8 +4,6 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.exc.StreamReadException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.dataformat.xml.XmlTestUtil; @@ -13,19 +11,17 @@ /** * Tests for [dataformat-xml#114]: Support for STRICT_DUPLICATE_DETECTION + * + * @since 2.21 */ public class StrictDuplicateDetection114Test extends XmlTestUtil { - static class TestBean { + static class TestBean114 { public String field1; public String field2; } - private final XmlMapper XML_MAPPER = XmlMapper.builder() - .enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION) - .build(); - - private final ObjectMapper JSON_MAPPER = JsonMapper.builder() + private final XmlMapper STRICT_MAPPER = XmlMapper.builder() .enable(JsonParser.Feature.STRICT_DUPLICATE_DETECTION) .build(); @@ -33,20 +29,11 @@ static class TestBean { @Test public void testStrictDuplicateDetectionWithPOJO() throws Exception { - // First verify JSON mapper properly rejects duplicates - final String jsonWithDup = "{\"field1\":\"value1\",\"field1\":\"value2\"}"; - - StreamReadException e = assertThrows(StreamReadException.class, () -> { - JSON_MAPPER.readValue(jsonWithDup, TestBean.class); - }); - assertTrue(e.getMessage().contains("Duplicate field"), - "Expected 'Duplicate field' error, got: " + e.getMessage()); - - // Now test XML mapper should also reject duplicates + // Test XML mapper should also reject duplicates final String xmlWithDup = "value1value2"; - e = assertThrows(StreamReadException.class, () -> { - XML_MAPPER.readValue(xmlWithDup, TestBean.class); + StreamReadException e = assertThrows(StreamReadException.class, () -> { + STRICT_MAPPER.readValue(xmlWithDup, TestBean114.class); }); assertTrue(e.getMessage().contains("Duplicate field"), "Expected 'Duplicate field' error, got: " + e.getMessage()); @@ -57,7 +44,7 @@ public void testNoDuplicatesShouldWork() throws Exception { final String xml = "value1value2"; - TestBean bean = XML_MAPPER.readValue(xml, TestBean.class); + TestBean114 bean = STRICT_MAPPER.readValue(xml, TestBean114.class); assertNotNull(bean); assertEquals("value1", bean.field1); assertEquals("value2", bean.field2); @@ -71,7 +58,7 @@ public void testDuplicateDetectionDisabledByDefault() throws Exception // Should allow duplicates by default (last value wins) final String xmlWithDup = "value1value2"; - TestBean bean = mapper.readValue(xmlWithDup, TestBean.class); + TestBean114 bean = mapper.readValue(xmlWithDup, TestBean114.class); assertNotNull(bean); assertEquals("value2", bean.field1); // last value wins } From 126594933069d59a98866451e64fc9d6654d3285 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 27 Oct 2025 16:20:37 -0700 Subject: [PATCH 4/5] ... and yet more --- .../dataformat/xml/deser/XmlReadContext.java | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java index 26ec15cc..20214793 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java @@ -84,6 +84,12 @@ public XmlReadContext(XmlReadContext parent, DupDetector dups, _nestingDepth = nestingDepth; } + @Deprecated // @since 2.21 + public XmlReadContext(XmlReadContext parent, int nestingDepth, + int type, int lineNr, int colNr) { + this(parent, null, nestingDepth, type, lineNr, colNr); + } + protected final void reset(int type, int lineNr, int colNr) { _type = type; @@ -96,7 +102,7 @@ protected final void reset(int type, int lineNr, int colNr) if (_dupDetector != null) { _dupDetector.reset(); } - // _nestingDepth fine as is, same level for reuse + // _nestingDepth fine as-is, same level for reuse } @Override @@ -119,6 +125,12 @@ public static XmlReadContext createRootContext(DupDetector dups, int lineNr, int return new XmlReadContext(null, dups, 0, TYPE_ROOT, lineNr, colNr); } + @Deprecated // @since 2.21 + public static XmlReadContext createRootContext(int lineNr, int colNr) { + return createRootContext(null, lineNr, colNr); + } + + @Deprecated // @since 2.21 public static XmlReadContext createRootContext() { return createRootContext(null, 1, 0); } @@ -196,18 +208,20 @@ public final void valueStarted() { public void setCurrentName(String name) throws JsonProcessingException { _currentName = name; - // Only check for duplicates in Object contexts, not in Arrays or Root - if (_dupDetector != null && _type == TYPE_OBJECT) { - if (_dupDetector.isDup(name)) { - // Use the parser's location for the error message - Object src = (_dupDetector == null) ? null : _dupDetector.getSource(); - throw new JsonParseException(null, - "Duplicate field '" + name + "'", startLocation( - (src instanceof ContentReference) ? (ContentReference) src : ContentReference.unknown())); - } + if (_dupDetector != null) { + _checkDup(_dupDetector, name); } } + // @since 2.21 + private static void _checkDup(DupDetector dd, String name) throws JsonProcessingException + { + if (dd.isDup(name)) { + throw new JsonParseException(null, + "Duplicate field '"+name+"'", dd.findLocation()); + } + } + public void setNamesToWrap(Set namesToWrap) { _namesToWrap = namesToWrap; } From 8fab7332109a55c1b10d670def5b0504c992e656 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 27 Oct 2025 17:15:28 -0700 Subject: [PATCH 5/5] Naming change to align with other formats --- .../dataformat/xml/deser/XmlReadContext.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java b/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java index 20214793..aa40167b 100644 --- a/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java +++ b/src/main/java/com/fasterxml/jackson/dataformat/xml/deser/XmlReadContext.java @@ -30,7 +30,7 @@ public final class XmlReadContext * * @since 2.21 */ - protected final DupDetector _dupDetector; + protected final DupDetector _dups; // // // Location information (minus source reference) @@ -77,7 +77,7 @@ public XmlReadContext(XmlReadContext parent, DupDetector dups, super(); _type = type; _parent = parent; - _dupDetector = dups; + _dups = dups; _lineNr = lineNr; _columnNr = colNr; _index = -1; @@ -99,8 +99,8 @@ protected final void reset(int type, int lineNr, int colNr) _currentName = null; _currentValue = null; _namesToWrap = null; - if (_dupDetector != null) { - _dupDetector.reset(); + if (_dups != null) { + _dups.reset(); } // _nestingDepth fine as-is, same level for reuse } @@ -141,7 +141,7 @@ public final XmlReadContext createChildArrayContext(int lineNr, int colNr) XmlReadContext ctxt = _child; if (ctxt == null) { _child = ctxt = new XmlReadContext(this, - (_dupDetector == null) ? null : _dupDetector.child(), + (_dups == null) ? null : _dups.child(), _nestingDepth+1, TYPE_ARRAY, lineNr, colNr); return ctxt; } @@ -155,7 +155,7 @@ public final XmlReadContext createChildObjectContext(int lineNr, int colNr) XmlReadContext ctxt = _child; if (ctxt == null) { _child = ctxt = new XmlReadContext(this, - (_dupDetector == null) ? null : _dupDetector.child(), + (_dups == null) ? null : _dups.child(), _nestingDepth+1, TYPE_OBJECT, lineNr, colNr); } else { ctxt.reset(TYPE_OBJECT, lineNr, colNr); @@ -208,8 +208,8 @@ public final void valueStarted() { public void setCurrentName(String name) throws JsonProcessingException { _currentName = name; - if (_dupDetector != null) { - _checkDup(_dupDetector, name); + if (_dups != null) { + _checkDup(_dups, name); } }