• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Jackson JSON-processor.
2  *
3  * Copyright (c) 2007- Tatu Saloranta, tatu.saloranta@iki.fi
4  */
5 
6 package com.fasterxml.jackson.core;
7 
8 import com.fasterxml.jackson.core.io.CharTypes;
9 
10 /**
11  * Shared base class for streaming processing contexts used during
12  * reading and writing of Json content using Streaming API.
13  * This context is also exposed to applications:
14  * context object can be used by applications to get an idea of
15  * relative position of the parser/generator within json content
16  * being processed. This allows for some contextual processing: for
17  * example, output within Array context can differ from that of
18  * Object context.
19  */
20 public abstract class JsonStreamContext
21 {
22     // // // Type constants used internally
23 
24     protected final static int TYPE_ROOT = 0;
25     protected final static int TYPE_ARRAY = 1;
26     protected final static int TYPE_OBJECT = 2;
27 
28     protected int _type;
29 
30     /**
31      * Index of the currently processed entry. Starts with -1 to signal
32      * that no entries have been started, and gets advanced each
33      * time a new entry is started, either by encountering an expected
34      * separator, or with new values if no separators are expected
35      * (the case for root context).
36      */
37     protected int _index;
38 
39     /*
40     /**********************************************************
41     /* Life-cycle
42     /**********************************************************
43      */
44 
JsonStreamContext()45     protected JsonStreamContext() { }
46 
47     /**
48      * Copy constructor used by sub-classes for creating copies for
49      * buffering.
50      *
51      * @since 2.9
52      */
JsonStreamContext(JsonStreamContext base)53     protected JsonStreamContext(JsonStreamContext base) {
54         _type = base._type;
55         _index = base._index;
56     }
57 
58     /**
59      * @since 2.9
60      */
JsonStreamContext(int type, int index)61     protected JsonStreamContext(int type, int index) {
62         _type = type;
63         _index = index;
64     }
65 
66     /*
67     /**********************************************************
68     /* Public API, accessors
69     /**********************************************************
70      */
71 
72     /**
73      * Accessor for finding parent context of this context; will
74      * return null for root context.
75      */
getParent()76     public abstract JsonStreamContext getParent();
77 
78     /**
79      * Method that returns true if this context is an Array context;
80      * that is, content is being read from or written to a Json Array.
81      */
inArray()82     public final boolean inArray() { return _type == TYPE_ARRAY; }
83 
84     /**
85      * Method that returns true if this context is a Root context;
86      * that is, content is being read from or written to without
87      * enclosing array or object structure.
88      */
inRoot()89     public final boolean inRoot() { return _type == TYPE_ROOT; }
90 
91     /**
92      * Method that returns true if this context is an Object context;
93      * that is, content is being read from or written to a Json Object.
94      */
inObject()95     public final boolean inObject() { return _type == TYPE_OBJECT; }
96 
97     /**
98      * Method for accessing simple type description of current context;
99      * either ROOT (for root-level values), OBJECT (for field names and
100      * values of JSON Objects) or ARRAY (for values of JSON Arrays)
101      *
102      * @deprecated Since 2.8 use {@link #typeDesc} instead
103      */
104     @Deprecated // since 2.8
getTypeDesc()105     public final String getTypeDesc() {
106         switch (_type) {
107         case TYPE_ROOT: return "ROOT";
108         case TYPE_ARRAY: return "ARRAY";
109         case TYPE_OBJECT: return "OBJECT";
110         }
111         return "?";
112     }
113 
114     /**
115      * @since 2.8
116      */
typeDesc()117     public String typeDesc() {
118         switch (_type) {
119         case TYPE_ROOT: return "root";
120         case TYPE_ARRAY: return "Array";
121         case TYPE_OBJECT: return "Object";
122         }
123         return "?";
124     }
125 
126     /**
127      * @return Number of entries that are complete and started.
128      */
getEntryCount()129     public final int getEntryCount() { return _index + 1; }
130 
131     /**
132      * @return Index of the currently processed entry, if any
133      */
getCurrentIndex()134     public final int getCurrentIndex() { return (_index < 0) ? 0 : _index; }
135 
136     /**
137      * Method that may be called to verify whether this context has valid index:
138      * will return `false` before the first entry of Object context or before
139      * first element of Array context; otherwise returns `true`.
140      *
141      * @since 2.9
142      */
hasCurrentIndex()143     public boolean hasCurrentIndex() { return _index >= 0; }
144 
145     /**
146      * Method that may be called to check if this context is either:
147      *<ul>
148      * <li>Object, with at least one entry written (partially or completely)
149      *  </li>
150      * <li>Array, with at least one entry written (partially or completely)
151      *  </li>
152      *</ul>
153      * and if so, return `true`; otherwise return `false`. Latter case includes
154      * Root context (always), and Object/Array contexts before any entries/elements
155      * have been read or written.
156      *<p>
157      * Method is mostly used to determine whether this context should be used for
158      * constructing {@link JsonPointer}
159      *
160      * @since 2.9
161      */
hasPathSegment()162     public boolean hasPathSegment() {
163         if (_type == TYPE_OBJECT) {
164             return hasCurrentName();
165         } else if (_type == TYPE_ARRAY) {
166             return hasCurrentIndex();
167         }
168         return false;
169     }
170 
171     /**
172      * Method for accessing name associated with the current location.
173      * Non-null for <code>FIELD_NAME</code> and value events that directly
174      * follow field names; null for root level and array values.
175      */
getCurrentName()176     public abstract String getCurrentName();
177 
178     /**
179      * @since 2.9
180      */
hasCurrentName()181     public boolean hasCurrentName() { return getCurrentName() != null; }
182 
183     /**
184      * Method for accessing currently active value being used by data-binding
185      * (as the source of streaming data to write, or destination of data being
186      * read), at this level in hierarchy.
187      *<p>
188      * Note that "current value" is NOT populated (or used) by Streaming parser or generator;
189      * it is only used by higher-level data-binding functionality.
190      * The reason it is included here is that it can be stored and accessed hierarchically,
191      * and gets passed through data-binding.
192      *
193      * @return Currently active value, if one has been assigned.
194      *
195      * @since 2.5
196      */
getCurrentValue()197     public Object getCurrentValue() {
198         return null;
199     }
200 
201     /**
202      * Method to call to pass value to be returned via {@link #getCurrentValue}; typically
203      * called indirectly through {@link JsonParser#setCurrentValue}
204      * or {@link JsonGenerator#setCurrentValue}).
205      *
206      * @since 2.5
207      */
setCurrentValue(Object v)208     public void setCurrentValue(Object v) { }
209 
210     /**
211      * Factory method for constructing a {@link JsonPointer} that points to the current
212      * location within the stream that this context is for, excluding information about
213      * "root context" (only relevant for multi-root-value cases)
214      *
215      * @since 2.9
216      */
pathAsPointer()217     public JsonPointer pathAsPointer() {
218         return JsonPointer.forPath(this, false);
219     }
220 
221     /**
222      * Factory method for constructing a {@link JsonPointer} that points to the current
223      * location within the stream that this context is for, optionally including
224      * "root value index"
225      *
226      * @param includeRoot Whether root-value offset is included as the first segment or not;
227      *
228      * @since 2.9
229      */
pathAsPointer(boolean includeRoot)230     public JsonPointer pathAsPointer(boolean includeRoot) {
231         return JsonPointer.forPath(this, includeRoot);
232     }
233 
234     /**
235      * Optional method that may be used to access starting location of this context:
236      * for example, in case of JSON `Object` context, offset at which `[` token was
237      * read or written. Often used for error reporting purposes.
238      * Implementations that do not keep track of such location are expected to return
239      * {@link JsonLocation#NA}; this is what the default implementation does.
240      *
241      * @return Location pointing to the point where the context
242      *   start marker was found (or written); never `null`.
243      *<p>
244      * NOTE: demoted from <code>JsonReadContext</code> in 2.9, to allow use for
245      * "non-standard" read contexts.
246      *
247      * @since 2.9
248      */
getStartLocation(Object srcRef)249     public JsonLocation getStartLocation(Object srcRef) {
250         return JsonLocation.NA;
251     }
252 
253     /**
254      * Overridden to provide developer readable "JsonPath" representation
255      * of the context.
256      *
257      * @since 2.9
258      */
259     @Override
toString()260     public String toString() {
261         StringBuilder sb = new StringBuilder(64);
262         switch (_type) {
263         case TYPE_ROOT:
264             sb.append("/");
265             break;
266         case TYPE_ARRAY:
267             sb.append('[');
268             sb.append(getCurrentIndex());
269             sb.append(']');
270             break;
271         case TYPE_OBJECT:
272         default:
273             sb.append('{');
274             String currentName = getCurrentName();
275             if (currentName != null) {
276                 sb.append('"');
277                 CharTypes.appendQuoted(sb, currentName);
278                 sb.append('"');
279             } else {
280                 sb.append('?');
281             }
282             sb.append('}');
283             break;
284         }
285         return sb.toString();
286     }
287 }
288