55import com .fasterxml .jackson .core .*;
66import com .fasterxml .jackson .core .io .CharTypes ;
77import com .fasterxml .jackson .core .io .ContentReference ;
8+ import com .fasterxml .jackson .core .json .DupDetector ;
89
910/**
1011 * Extension of {@link JsonStreamContext}, which implements
@@ -23,6 +24,14 @@ public final class XmlReadContext
2324
2425 protected final XmlReadContext _parent ;
2526
27+ /**
28+ * Object used for checking for duplicate field names, if enabled
29+ * (null if not enabled)
30+ *
31+ * @since 2.21
32+ */
33+ protected final DupDetector _dups ;
34+
2635 // // // Location information (minus source reference)
2736
2837 protected int _lineNr ;
@@ -59,28 +68,26 @@ public final class XmlReadContext
5968 */
6069
6170 /**
62- * @since 2.18
71+ * @since 2.21
6372 */
64- public XmlReadContext (XmlReadContext parent , int nestingDepth ,
73+ public XmlReadContext (XmlReadContext parent , DupDetector dups ,
74+ int nestingDepth ,
6575 int type , int lineNr , int colNr )
6676 {
6777 super ();
6878 _type = type ;
6979 _parent = parent ;
80+ _dups = dups ;
7081 _lineNr = lineNr ;
7182 _columnNr = colNr ;
7283 _index = -1 ;
7384 _nestingDepth = nestingDepth ;
7485 }
7586
76- /**
77- * @deprecated Since 2.18
78- */
79- @ Deprecated // since 2.18
80- public XmlReadContext (XmlReadContext parent , int type , int lineNr , int colNr )
81- {
82- this (parent , (parent == null ) ? 0 : parent ._nestingDepth + 1 ,
83- type , lineNr , colNr );
87+ @ Deprecated // @since 2.21
88+ public XmlReadContext (XmlReadContext parent , int nestingDepth ,
89+ int type , int lineNr , int colNr ) {
90+ this (parent , null , nestingDepth , type , lineNr , colNr );
8491 }
8592
8693 protected final void reset (int type , int lineNr , int colNr )
@@ -92,7 +99,10 @@ protected final void reset(int type, int lineNr, int colNr)
9299 _currentName = null ;
93100 _currentValue = null ;
94101 _namesToWrap = null ;
95- // _nestingDepth fine as is, same level for reuse
102+ if (_dups != null ) {
103+ _dups .reset ();
104+ }
105+ // _nestingDepth fine as-is, same level for reuse
96106 }
97107
98108 @ Override
@@ -111,20 +121,28 @@ public void setCurrentValue(Object v) {
111121 /**********************************************************************
112122 */
113123
124+ public static XmlReadContext createRootContext (DupDetector dups , int lineNr , int colNr ) {
125+ return new XmlReadContext (null , dups , 0 , TYPE_ROOT , lineNr , colNr );
126+ }
127+
128+ @ Deprecated // @since 2.21
114129 public static XmlReadContext createRootContext (int lineNr , int colNr ) {
115- return new XmlReadContext (null , 0 , TYPE_ROOT , lineNr , colNr );
130+ return createRootContext (null , lineNr , colNr );
116131 }
117132
133+ @ Deprecated // @since 2.21
118134 public static XmlReadContext createRootContext () {
119- return new XmlReadContext (null , 0 , TYPE_ROOT , 1 , 0 );
135+ return createRootContext (null , 1 , 0 );
120136 }
121-
137+
122138 public final XmlReadContext createChildArrayContext (int lineNr , int colNr )
123139 {
124140 ++_index ; // not needed for Object, but does not hurt so no need to check curr type
125141 XmlReadContext ctxt = _child ;
126142 if (ctxt == null ) {
127- _child = ctxt = new XmlReadContext (this , _nestingDepth +1 , TYPE_ARRAY , lineNr , colNr );
143+ _child = ctxt = new XmlReadContext (this ,
144+ (_dups == null ) ? null : _dups .child (),
145+ _nestingDepth +1 , TYPE_ARRAY , lineNr , colNr );
128146 return ctxt ;
129147 }
130148 ctxt .reset (TYPE_ARRAY , lineNr , colNr );
@@ -136,10 +154,12 @@ public final XmlReadContext createChildObjectContext(int lineNr, int colNr)
136154 ++_index ; // not needed for Object, but does not hurt so no need to check curr type
137155 XmlReadContext ctxt = _child ;
138156 if (ctxt == null ) {
139- _child = ctxt = new XmlReadContext (this , TYPE_OBJECT , lineNr , colNr );
140- return ctxt ;
157+ _child = ctxt = new XmlReadContext (this ,
158+ (_dups == null ) ? null : _dups .child (),
159+ _nestingDepth +1 , TYPE_OBJECT , lineNr , colNr );
160+ } else {
161+ ctxt .reset (TYPE_OBJECT , lineNr , colNr );
141162 }
142- ctxt .reset (TYPE_OBJECT , lineNr , colNr );
143163 return ctxt ;
144164 }
145165
@@ -186,10 +206,22 @@ public final void valueStarted() {
186206 ++_index ;
187207 }
188208
189- public void setCurrentName (String name ) {
209+ public void setCurrentName (String name ) throws JsonProcessingException {
190210 _currentName = name ;
211+ if (_dups != null ) {
212+ _checkDup (_dups , name );
213+ }
191214 }
192215
216+ // @since 2.21
217+ private static void _checkDup (DupDetector dd , String name ) throws JsonProcessingException
218+ {
219+ if (dd .isDup (name )) {
220+ throw new JsonParseException (null ,
221+ "Duplicate field '" +name +"'" , dd .findLocation ());
222+ }
223+ }
224+
193225 public void setNamesToWrap (Set <String > namesToWrap ) {
194226 _namesToWrap = namesToWrap ;
195227 }
0 commit comments