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