• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 generator implementation classes.
9  */
10 public class JsonWriteContext extends JsonStreamContext
11 {
12     // // // Return values for writeValue()
13 
14     public final static int STATUS_OK_AS_IS = 0;
15     public final static int STATUS_OK_AFTER_COMMA = 1;
16     public final static int STATUS_OK_AFTER_COLON = 2;
17     public final static int STATUS_OK_AFTER_SPACE = 3; // in root context
18     public final static int STATUS_EXPECT_VALUE = 4;
19     public final static int STATUS_EXPECT_NAME = 5;
20 
21     /**
22      * Parent context for this context; null for root context.
23      */
24     protected final JsonWriteContext _parent;
25 
26     // // // Optional duplicate detection
27 
28     protected DupDetector _dups;
29 
30     /*
31     /**********************************************************
32     /* Simple instance reuse slots; speed up things a bit (10-15%)
33     /* for docs with lots of small arrays/objects
34     /**********************************************************
35      */
36 
37     protected JsonWriteContext _child;
38 
39     /*
40     /**********************************************************
41     /* Location/state information (minus source reference)
42     /**********************************************************
43      */
44 
45     /**
46      * Name of the field of which value is to be written; only
47      * used for OBJECT contexts
48      */
49     protected String _currentName;
50 
51     /**
52      * @since 2.5
53      */
54     protected Object _currentValue;
55 
56     /**
57      * Marker used to indicate that we just wrote a name, and
58      * now expect a value to write
59      */
60     protected boolean _gotName;
61 
62     /*
63     /**********************************************************
64     /* Life-cycle
65     /**********************************************************
66      */
67 
JsonWriteContext(int type, JsonWriteContext parent, DupDetector dups)68     protected JsonWriteContext(int type, JsonWriteContext parent, DupDetector dups) {
69         super();
70         _type = type;
71         _parent = parent;
72         _dups = dups;
73         _index = -1;
74     }
75 
76     /* @since 2.10 */
JsonWriteContext(int type, JsonWriteContext parent, DupDetector dups, Object currValue)77     protected JsonWriteContext(int type, JsonWriteContext parent, DupDetector dups,
78             Object currValue) {
79         super();
80         _type = type;
81         _parent = parent;
82         _dups = dups;
83         _index = -1;
84         _currentValue = currValue;
85     }
86 
reset(int type)87     protected JsonWriteContext reset(int type) {
88         _type = type;
89         _index = -1;
90         _currentName = null;
91         _gotName = false;
92         _currentValue = null;
93         if (_dups != null) { _dups.reset(); }
94         return this;
95     }
96 
97     /* @since 2.10 */
reset(int type, Object currValue)98     protected JsonWriteContext reset(int type, Object currValue) {
99         _type = type;
100         _index = -1;
101         _currentName = null;
102         _gotName = false;
103         _currentValue = currValue;
104         if (_dups != null) { _dups.reset(); }
105         return this;
106     }
107 
withDupDetector(DupDetector dups)108     public JsonWriteContext withDupDetector(DupDetector dups) {
109         _dups = dups;
110         return this;
111     }
112 
113     @Override
getCurrentValue()114     public Object getCurrentValue() {
115         return _currentValue;
116     }
117 
118     @Override
setCurrentValue(Object v)119     public void setCurrentValue(Object v) {
120         _currentValue = v;
121     }
122 
123     /*
124     /**********************************************************
125     /* Factory methods
126     /**********************************************************
127      */
128 
129     /**
130      * @deprecated Since 2.3; use method that takes argument
131      */
132     @Deprecated
createRootContext()133     public static JsonWriteContext createRootContext() { return createRootContext(null); }
134 
createRootContext(DupDetector dd)135     public static JsonWriteContext createRootContext(DupDetector dd) {
136         return new JsonWriteContext(TYPE_ROOT, null, dd);
137     }
138 
createChildArrayContext()139     public JsonWriteContext createChildArrayContext() {
140         JsonWriteContext ctxt = _child;
141         if (ctxt == null) {
142             _child = ctxt = new JsonWriteContext(TYPE_ARRAY, this,
143                     (_dups == null) ? null : _dups.child());
144             return ctxt;
145         }
146         return ctxt.reset(TYPE_ARRAY);
147     }
148 
149     /* @since 2.10 */
createChildArrayContext(Object currValue)150     public JsonWriteContext createChildArrayContext(Object currValue) {
151         JsonWriteContext ctxt = _child;
152         if (ctxt == null) {
153             _child = ctxt = new JsonWriteContext(TYPE_ARRAY, this,
154                     (_dups == null) ? null : _dups.child(), currValue);
155             return ctxt;
156         }
157         return ctxt.reset(TYPE_ARRAY, currValue);
158     }
159 
createChildObjectContext()160     public JsonWriteContext createChildObjectContext() {
161         JsonWriteContext ctxt = _child;
162         if (ctxt == null) {
163             _child = ctxt = new JsonWriteContext(TYPE_OBJECT, this,
164                     (_dups == null) ? null : _dups.child());
165             return ctxt;
166         }
167         return ctxt.reset(TYPE_OBJECT);
168     }
169 
170     /* @since 2.10 */
createChildObjectContext(Object currValue)171     public JsonWriteContext createChildObjectContext(Object currValue) {
172         JsonWriteContext ctxt = _child;
173         if (ctxt == null) {
174             _child = ctxt = new JsonWriteContext(TYPE_OBJECT, this,
175                     (_dups == null) ? null : _dups.child(), currValue);
176             return ctxt;
177         }
178         return ctxt.reset(TYPE_OBJECT, currValue);
179     }
180 
getParent()181     @Override public final JsonWriteContext getParent() { return _parent; }
getCurrentName()182     @Override public final String getCurrentName() { return _currentName; }
183     // @since 2.9
hasCurrentName()184     @Override public boolean hasCurrentName() { return _currentName != null; }
185 
186     /**
187      * Method that can be used to both clear the accumulated references
188      * (specifically value set with {@link #setCurrentValue(Object)})
189      * that should not be retained, and returns parent (as would
190      * {@link #getParent()} do). Typically called when closing the active
191      * context when encountering {@link JsonToken#END_ARRAY} or
192      * {@link JsonToken#END_OBJECT}.
193      *
194      * @since 2.7
195      */
clearAndGetParent()196     public JsonWriteContext clearAndGetParent() {
197         _currentValue = null;
198         // could also clear the current name, but seems cheap enough to leave?
199         return _parent;
200     }
201 
getDupDetector()202     public DupDetector getDupDetector() {
203         return _dups;
204     }
205 
206     /**
207      * Method that writer is to call before it writes a field name.
208      *
209      * @return Index of the field entry (0-based)
210      */
writeFieldName(String name)211     public int writeFieldName(String name) throws JsonProcessingException {
212         if ((_type != TYPE_OBJECT) || _gotName) {
213             return STATUS_EXPECT_VALUE;
214         }
215         _gotName = true;
216         _currentName = name;
217         if (_dups != null) { _checkDup(_dups, name); }
218         return (_index < 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_COMMA;
219     }
220 
_checkDup(DupDetector dd, String name)221     private final void _checkDup(DupDetector dd, String name) throws JsonProcessingException {
222         if (dd.isDup(name)) {
223             Object src = dd.getSource();
224             throw new JsonGenerationException("Duplicate field '"+name+"'",
225                     ((src instanceof JsonGenerator) ? ((JsonGenerator) src) : null));
226         }
227     }
228 
writeValue()229     public int writeValue() {
230         // Most likely, object:
231         if (_type == TYPE_OBJECT) {
232             if (!_gotName) {
233                 return STATUS_EXPECT_NAME;
234             }
235             _gotName = false;
236             ++_index;
237             return STATUS_OK_AFTER_COLON;
238         }
239 
240         // Ok, array?
241         if (_type == TYPE_ARRAY) {
242             int ix = _index;
243             ++_index;
244             return (ix < 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_COMMA;
245         }
246 
247         // Nope, root context
248         // No commas within root context, but need space
249         ++_index;
250         return (_index == 0) ? STATUS_OK_AS_IS : STATUS_OK_AFTER_SPACE;
251     }
252 }
253