1 package com.fasterxml.jackson.core.json;
2
3 import com.fasterxml.jackson.core.*;
4
5 /**
6 * Extension of {@link JsonStreamContext}, which implements
7 * core methods needed, and also exposes
8 * more complete API to parser implementation classes.
9 */
10 public final class JsonReadContext extends JsonStreamContext
11 {
12 // // // Configuration
13
14 /**
15 * Parent context for this context; null for root context.
16 */
17 protected final JsonReadContext _parent;
18
19 // // // Optional duplicate detection
20
21 protected DupDetector _dups;
22
23 /*
24 /**********************************************************
25 /* Simple instance reuse slots; speeds up things
26 /* a bit (10-15%) for docs with lots of small
27 /* arrays/objects (for which allocation was
28 /* visible in profile stack frames)
29 /**********************************************************
30 */
31
32 protected JsonReadContext _child;
33
34 /*
35 /**********************************************************
36 /* Location/state information (minus source reference)
37 /**********************************************************
38 */
39
40 protected String _currentName;
41
42 /**
43 * @since 2.5
44 */
45 protected Object _currentValue;
46
47 protected int _lineNr;
48 protected int _columnNr;
49
50 /*
51 /**********************************************************
52 /* Instance construction, config, reuse
53 /**********************************************************
54 */
55
56 public JsonReadContext(JsonReadContext parent, DupDetector dups, int type, int lineNr, int colNr) {
57 super();
58 _parent = parent;
59 _dups = dups;
60 _type = type;
61 _lineNr = lineNr;
62 _columnNr = colNr;
63 _index = -1;
64 }
65
66 protected void reset(int type, int lineNr, int colNr) {
67 _type = type;
68 _index = -1;
69 _lineNr = lineNr;
70 _columnNr = colNr;
71 _currentName = null;
72 _currentValue = null;
73 if (_dups != null) {
74 _dups.reset();
75 }
76 }
77
78 /*
79 public void trackDups(JsonParser p) {
80 _dups = DupDetector.rootDetector(p);
81 }
82 */
83
84 public JsonReadContext withDupDetector(DupDetector dups) {
85 _dups = dups;
86 return this;
87 }
88
89 @Override
90 public Object getCurrentValue() {
91 return _currentValue;
92 }
93
94 @Override
95 public void setCurrentValue(Object v) {
96 _currentValue = v;
97 }
98
99 /*
100 /**********************************************************
101 /* Factory methods
102 /**********************************************************
103 */
104
105 public static JsonReadContext createRootContext(int lineNr, int colNr, DupDetector dups) {
106 return new JsonReadContext(null, dups, TYPE_ROOT, lineNr, colNr);
107 }
108
109 public static JsonReadContext createRootContext(DupDetector dups) {
110 return new JsonReadContext(null, dups, TYPE_ROOT, 1, 0);
111 }
112
113 public JsonReadContext createChildArrayContext(int lineNr, int colNr) {
114 JsonReadContext ctxt = _child;
115 if (ctxt == null) {
116 _child = ctxt = new JsonReadContext(this,
117 (_dups == null) ? null : _dups.child(), TYPE_ARRAY, lineNr, colNr);
118 } else {
119 ctxt.reset(TYPE_ARRAY, lineNr, colNr);
120 }
121 return ctxt;
122 }
123
124 public JsonReadContext createChildObjectContext(int lineNr, int colNr) {
125 JsonReadContext ctxt = _child;
126 if (ctxt == null) {
127 _child = ctxt = new JsonReadContext(this,
128 (_dups == null) ? null : _dups.child(), TYPE_OBJECT, lineNr, colNr);
129 return ctxt;
130 }
131 ctxt.reset(TYPE_OBJECT, lineNr, colNr);
132 return ctxt;
133 }
134
135 /*
136 /**********************************************************
137 /* Abstract method implementations, overrides
138 /**********************************************************
139 */
140
141 @Override public String getCurrentName() { return _currentName; }
142
143 // @since 2.9
144 @Override public boolean hasCurrentName() { return _currentName != null; }
145
146 @Override public JsonReadContext getParent() { return _parent; }
147
148 @Override
149 public JsonLocation getStartLocation(Object srcRef) {
150 // We don't keep track of offsets at this level (only reader does)
151 long totalChars = -1L;
152 return new JsonLocation(srcRef, totalChars, _lineNr, _columnNr);
153 }
154
155 /*
156 /**********************************************************
157 /* Extended API
158 /**********************************************************
159 */
160
161 /**
162 * Method that can be used to both clear the accumulated references
163 * (specifically value set with {@link #setCurrentValue(Object)})
164 * that should not be retained, and returns parent (as would
165 * {@link #getParent()} do). Typically called when closing the active
166 * context when encountering {@link JsonToken#END_ARRAY} or
167 * {@link JsonToken#END_OBJECT}.
168 *
169 * @since 2.7
170 */
171 public JsonReadContext clearAndGetParent() {
172 _currentValue = null;
173 // could also clear the current name, but seems cheap enough to leave?
174 return _parent;
175 }
176
177 public DupDetector getDupDetector() {
178 return _dups;
179 }
180
181 /*
182 /**********************************************************
183 /* State changes
184 /**********************************************************
185 */
186
187 public boolean expectComma() {
188 /* Assumption here is that we will be getting a value (at least
189 * before calling this method again), and
190 * so will auto-increment index to avoid having to do another call
191 */
192 int ix = ++_index; // starts from -1
193 return (_type != TYPE_ROOT && ix > 0);
194 }
195
196 public void setCurrentName(String name) throws JsonProcessingException {
197 _currentName = name;
198 if (_dups != null) { _checkDup(_dups, name); }
199 }
200
201 private void _checkDup(DupDetector dd, String name) throws JsonProcessingException {
202 if (dd.isDup(name)) {
203 Object src = dd.getSource();
204 throw new JsonParseException(((src instanceof JsonParser) ? ((JsonParser) src) : null),
205 "Duplicate field '"+name+"'");
206 }
207 }
208 }
209