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