blob: 78e4ff56477717c5e383c1e38b8f4e621a142712 [file] [log] [blame]
Tatu Salorantadfd69092015-04-09 22:29:34 -07001package com.fasterxml.jackson.core.filter;
2
3import java.io.IOException;
4import java.io.OutputStream;
5import java.math.BigDecimal;
6import java.math.BigInteger;
7
8import com.fasterxml.jackson.core.*;
9import com.fasterxml.jackson.core.util.JsonParserDelegate;
10
11/**
12 * Specialized {@link JsonParserDelegate} that allows use of
13 * {@link TokenFilter} for outputting a subset of content that
14 * is visible to caller
15 *
16 * @since 2.6
17 */
18public class FilteringParserDelegate extends JsonParserDelegate
19{
20 /*
21 /**********************************************************
22 /* Configuration
23 /**********************************************************
24 */
25
26 /**
27 * Object consulted to determine whether to write parts of content generator
28 * is asked to write or not.
29 */
30 protected TokenFilter rootFilter;
31
32 /**
33 * Flag that determines whether filtering will continue after the first
34 * match is indicated or not: if `false`, output is based on just the first
35 * full match (returning {@link TokenFilter#INCLUDE_ALL}) and no more
36 * checks are made; if `true` then filtering will be applied as necessary
37 * until end of content.
38 */
39 protected boolean _allowMultipleMatches;
40
41 /**
42 * Flag that determines whether path leading up to included content should
43 * also be automatically included or not. If `false`, no path inclusion is
44 * done and only explicitly included entries are output; if `true` then
45 * path from main level down to match is also included as necessary.
46 */
47 protected boolean _includePath;
48
49 /*
50 /**********************************************************
51 /* State
52 /**********************************************************
53 */
54
55 /**
56 * Last token retrieved via {@link #nextToken}, if any.
57 * Null before the first call to <code>nextToken()</code>,
58 * as well as if token has been explicitly cleared
59 */
60 protected JsonToken _currToken;
61
62 /**
63 * Last cleared token, if any: that is, value that was in
64 * effect when {@link #clearCurrentToken} was called.
65 */
66 protected JsonToken _lastClearedToken;
67
68 /**
69 * Although delegate has its own output context it is not sufficient since we actually
70 * have to keep track of excluded (filtered out) structures as well as ones delegate
71 * actually outputs.
72 */
73 protected TokenFilterContext _filterContext;
74
75 /**
Tatu Saloranta5a5d1192015-04-13 23:05:07 -070076 * When parent tokens are buffered (during checking whether child tokens included),
77 * we need to keep a reference back to the context closest to root that is yet to
78 * be exposed.
79 */
80 protected TokenFilterContext _replayContext;
81
82 /**
Tatu Salorantadfd69092015-04-09 22:29:34 -070083 * State that applies to the item within container, used where applicable.
84 * Specifically used to pass inclusion state between property name and
85 * property, and also used for array elements.
86 */
87 protected TokenFilter _itemFilter;
88
89 /**
90 * Number of tokens for which {@link TokenFilter#INCLUDE_ALL}
Tatu Saloranta5a5d1192015-04-13 23:05:07 -070091 * has been returned.
Tatu Salorantadfd69092015-04-09 22:29:34 -070092 */
93 protected int _matchCount;
94
95 /*
96 /**********************************************************
97 /* Construction, initialization
98 /**********************************************************
99 */
100
101 public FilteringParserDelegate(JsonParser p, TokenFilter f,
102 boolean includePath, boolean allowMultipleMatches)
103 {
104 super(p);
105 rootFilter = f;
106 // and this is the currently active filter for root values
107 _itemFilter = f;
108 _filterContext = TokenFilterContext.createRootContext(f);
109 _includePath = includePath;
110 _allowMultipleMatches = allowMultipleMatches;
111 }
112
113 /*
114 /**********************************************************
115 /* Extended API
116 /**********************************************************
117 */
118
119 public TokenFilter getFilter() { return rootFilter; }
120
121 /**
122 * Accessor for finding number of matches, where specific token and sub-tree
123 * starting (if structured type) are passed.
124 */
125 public int getMatchCount() {
126 return _matchCount;
127 }
128
129 /*
130 /**********************************************************
131 /* Public API, token accessors
132 /**********************************************************
133 */
134
135 @Override public JsonToken getCurrentToken() { return _currToken; }
136
137 @Override public final int getCurrentTokenId() {
138 final JsonToken t = _currToken;
139 return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id();
140 }
141
142 @Override public boolean hasCurrentToken() { return _currToken != null; }
143 @Override public boolean hasTokenId(int id) {
144 final JsonToken t = _currToken;
145 if (t == null) {
146 return (JsonTokenId.ID_NO_TOKEN == id);
147 }
148 return t.id() == id;
149 }
150
151 @Override public final boolean hasToken(JsonToken t) {
152 return (_currToken == t);
153 }
154
155 @Override public boolean isExpectedStartArrayToken() { return _currToken == JsonToken.START_ARRAY; }
156 @Override public boolean isExpectedStartObjectToken() { return _currToken == JsonToken.START_OBJECT; }
157
158 @Override public JsonLocation getCurrentLocation() { return delegate.getCurrentLocation(); }
159 @Override public JsonStreamContext getParsingContext() { return _filterContext; }
160
161 // !!! TODO: not necessarily correct...
162 @Override public String getCurrentName() throws IOException { return delegate.getCurrentName(); }
163
164 /*
165 /**********************************************************
166 /* Public API, token state overrides
167 /**********************************************************
168 */
169
170 @Override
171 public void clearCurrentToken() {
172 if (_currToken != null) {
173 _lastClearedToken = _currToken;
174 _currToken = null;
175 }
176 }
177
178 @Override
179 public JsonToken getLastClearedToken() { return _lastClearedToken; }
180
181 // !!! TODO: re-implement
182 @Override
183 public void overrideCurrentName(String name) { delegate.overrideCurrentName(name); }
184
185 /*
186 /**********************************************************
187 /* Public API, traversal
188 /**********************************************************
189 */
190
191 // !!! TODO: re-implement
192 @Override public JsonToken nextToken() throws IOException { return delegate.nextToken(); }
193
194 @Override
195 public JsonToken nextValue() throws IOException {
196 // Re-implemented same as ParserMinimalBase:
197 JsonToken t = nextToken();
198 if (t == JsonToken.FIELD_NAME) {
199 t = nextToken();
200 }
201 return t;
202 }
203
204 /**
205 * Need to override, re-implement similar to how method defined in
206 * {@link com.fasterxml.jackson.core.base.ParserMinimalBase}, to keep
207 * state correct here.
208 */
209 @Override
210 public JsonParser skipChildren() throws IOException
211 {
212 if (_currToken != JsonToken.START_OBJECT
213 && _currToken != JsonToken.START_ARRAY) {
214 return this;
215 }
216 int open = 1;
217
218 // Since proper matching of start/end markers is handled
219 // by nextToken(), we'll just count nesting levels here
220 while (true) {
221 JsonToken t = nextToken();
222 if (t == null) { // not ideal but for now, just return
223 return this;
224 }
225 if (t.isStructStart()) {
226 ++open;
227 } else if (t.isStructEnd()) {
228 if (--open == 0) {
229 return this;
230 }
231 }
232 }
233 }
234
235 /*
236 /**********************************************************
237 /* Public API, access to token information, text
238 /**********************************************************
239 */
240
241 @Override public String getText() throws IOException { return delegate.getText(); }
242 @Override public boolean hasTextCharacters() { return delegate.hasTextCharacters(); }
243 @Override public char[] getTextCharacters() throws IOException { return delegate.getTextCharacters(); }
244 @Override public int getTextLength() throws IOException { return delegate.getTextLength(); }
245 @Override public int getTextOffset() throws IOException { return delegate.getTextOffset(); }
246
247 /*
248 /**********************************************************
249 /* Public API, access to token information, numeric
250 /**********************************************************
251 */
252
253 @Override
254 public BigInteger getBigIntegerValue() throws IOException { return delegate.getBigIntegerValue(); }
255
256 @Override
257 public boolean getBooleanValue() throws IOException { return delegate.getBooleanValue(); }
258
259 @Override
260 public byte getByteValue() throws IOException { return delegate.getByteValue(); }
261
262 @Override
263 public short getShortValue() throws IOException { return delegate.getShortValue(); }
264
265 @Override
266 public BigDecimal getDecimalValue() throws IOException { return delegate.getDecimalValue(); }
267
268 @Override
269 public double getDoubleValue() throws IOException { return delegate.getDoubleValue(); }
270
271 @Override
272 public float getFloatValue() throws IOException { return delegate.getFloatValue(); }
273
274 @Override
275 public int getIntValue() throws IOException { return delegate.getIntValue(); }
276
277 @Override
278 public long getLongValue() throws IOException { return delegate.getLongValue(); }
279
280 @Override
281 public NumberType getNumberType() throws IOException { return delegate.getNumberType(); }
282
283 @Override
284 public Number getNumberValue() throws IOException { return delegate.getNumberValue(); }
285
286 /*
287 /**********************************************************
288 /* Public API, access to token information, coercion/conversion
289 /**********************************************************
290 */
291
292 @Override public int getValueAsInt() throws IOException { return delegate.getValueAsInt(); }
293 @Override public int getValueAsInt(int defaultValue) throws IOException { return delegate.getValueAsInt(defaultValue); }
294 @Override public long getValueAsLong() throws IOException { return delegate.getValueAsLong(); }
295 @Override public long getValueAsLong(long defaultValue) throws IOException { return delegate.getValueAsLong(defaultValue); }
296 @Override public double getValueAsDouble() throws IOException { return delegate.getValueAsDouble(); }
297 @Override public double getValueAsDouble(double defaultValue) throws IOException { return delegate.getValueAsDouble(defaultValue); }
298 @Override public boolean getValueAsBoolean() throws IOException { return delegate.getValueAsBoolean(); }
299 @Override public boolean getValueAsBoolean(boolean defaultValue) throws IOException { return delegate.getValueAsBoolean(defaultValue); }
300 @Override public String getValueAsString() throws IOException { return delegate.getValueAsString(); }
301 @Override public String getValueAsString(String defaultValue) throws IOException { return delegate.getValueAsString(defaultValue); }
302
303 /*
304 /**********************************************************
305 /* Public API, access to token values, other
306 /**********************************************************
307 */
308
309 @Override public Object getEmbeddedObject() throws IOException { return delegate.getEmbeddedObject(); }
310 @Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException { return delegate.getBinaryValue(b64variant); }
311 @Override public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException { return delegate.readBinaryValue(b64variant, out); }
312 @Override public JsonLocation getTokenLocation() { return delegate.getTokenLocation(); }
313}