blob: 18750d163524d2150cf2fb86fbb4623f944a947f [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 /**
76 * State that applies to the item within container, used where applicable.
77 * Specifically used to pass inclusion state between property name and
78 * property, and also used for array elements.
79 */
80 protected TokenFilter _itemFilter;
81
82 /**
83 * Number of tokens for which {@link TokenFilter#INCLUDE_ALL}
84 * has been returned
85 */
86 protected int _matchCount;
87
88 /*
89 /**********************************************************
90 /* Construction, initialization
91 /**********************************************************
92 */
93
94 public FilteringParserDelegate(JsonParser p, TokenFilter f,
95 boolean includePath, boolean allowMultipleMatches)
96 {
97 super(p);
98 rootFilter = f;
99 // and this is the currently active filter for root values
100 _itemFilter = f;
101 _filterContext = TokenFilterContext.createRootContext(f);
102 _includePath = includePath;
103 _allowMultipleMatches = allowMultipleMatches;
104 }
105
106 /*
107 /**********************************************************
108 /* Extended API
109 /**********************************************************
110 */
111
112 public TokenFilter getFilter() { return rootFilter; }
113
114 /**
115 * Accessor for finding number of matches, where specific token and sub-tree
116 * starting (if structured type) are passed.
117 */
118 public int getMatchCount() {
119 return _matchCount;
120 }
121
122 /*
123 /**********************************************************
124 /* Public API, token accessors
125 /**********************************************************
126 */
127
128 @Override public JsonToken getCurrentToken() { return _currToken; }
129
130 @Override public final int getCurrentTokenId() {
131 final JsonToken t = _currToken;
132 return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id();
133 }
134
135 @Override public boolean hasCurrentToken() { return _currToken != null; }
136 @Override public boolean hasTokenId(int id) {
137 final JsonToken t = _currToken;
138 if (t == null) {
139 return (JsonTokenId.ID_NO_TOKEN == id);
140 }
141 return t.id() == id;
142 }
143
144 @Override public final boolean hasToken(JsonToken t) {
145 return (_currToken == t);
146 }
147
148 @Override public boolean isExpectedStartArrayToken() { return _currToken == JsonToken.START_ARRAY; }
149 @Override public boolean isExpectedStartObjectToken() { return _currToken == JsonToken.START_OBJECT; }
150
151 @Override public JsonLocation getCurrentLocation() { return delegate.getCurrentLocation(); }
152 @Override public JsonStreamContext getParsingContext() { return _filterContext; }
153
154 // !!! TODO: not necessarily correct...
155 @Override public String getCurrentName() throws IOException { return delegate.getCurrentName(); }
156
157 /*
158 /**********************************************************
159 /* Public API, token state overrides
160 /**********************************************************
161 */
162
163 @Override
164 public void clearCurrentToken() {
165 if (_currToken != null) {
166 _lastClearedToken = _currToken;
167 _currToken = null;
168 }
169 }
170
171 @Override
172 public JsonToken getLastClearedToken() { return _lastClearedToken; }
173
174 // !!! TODO: re-implement
175 @Override
176 public void overrideCurrentName(String name) { delegate.overrideCurrentName(name); }
177
178 /*
179 /**********************************************************
180 /* Public API, traversal
181 /**********************************************************
182 */
183
184 // !!! TODO: re-implement
185 @Override public JsonToken nextToken() throws IOException { return delegate.nextToken(); }
186
187 @Override
188 public JsonToken nextValue() throws IOException {
189 // Re-implemented same as ParserMinimalBase:
190 JsonToken t = nextToken();
191 if (t == JsonToken.FIELD_NAME) {
192 t = nextToken();
193 }
194 return t;
195 }
196
197 /**
198 * Need to override, re-implement similar to how method defined in
199 * {@link com.fasterxml.jackson.core.base.ParserMinimalBase}, to keep
200 * state correct here.
201 */
202 @Override
203 public JsonParser skipChildren() throws IOException
204 {
205 if (_currToken != JsonToken.START_OBJECT
206 && _currToken != JsonToken.START_ARRAY) {
207 return this;
208 }
209 int open = 1;
210
211 // Since proper matching of start/end markers is handled
212 // by nextToken(), we'll just count nesting levels here
213 while (true) {
214 JsonToken t = nextToken();
215 if (t == null) { // not ideal but for now, just return
216 return this;
217 }
218 if (t.isStructStart()) {
219 ++open;
220 } else if (t.isStructEnd()) {
221 if (--open == 0) {
222 return this;
223 }
224 }
225 }
226 }
227
228 /*
229 /**********************************************************
230 /* Public API, access to token information, text
231 /**********************************************************
232 */
233
234 @Override public String getText() throws IOException { return delegate.getText(); }
235 @Override public boolean hasTextCharacters() { return delegate.hasTextCharacters(); }
236 @Override public char[] getTextCharacters() throws IOException { return delegate.getTextCharacters(); }
237 @Override public int getTextLength() throws IOException { return delegate.getTextLength(); }
238 @Override public int getTextOffset() throws IOException { return delegate.getTextOffset(); }
239
240 /*
241 /**********************************************************
242 /* Public API, access to token information, numeric
243 /**********************************************************
244 */
245
246 @Override
247 public BigInteger getBigIntegerValue() throws IOException { return delegate.getBigIntegerValue(); }
248
249 @Override
250 public boolean getBooleanValue() throws IOException { return delegate.getBooleanValue(); }
251
252 @Override
253 public byte getByteValue() throws IOException { return delegate.getByteValue(); }
254
255 @Override
256 public short getShortValue() throws IOException { return delegate.getShortValue(); }
257
258 @Override
259 public BigDecimal getDecimalValue() throws IOException { return delegate.getDecimalValue(); }
260
261 @Override
262 public double getDoubleValue() throws IOException { return delegate.getDoubleValue(); }
263
264 @Override
265 public float getFloatValue() throws IOException { return delegate.getFloatValue(); }
266
267 @Override
268 public int getIntValue() throws IOException { return delegate.getIntValue(); }
269
270 @Override
271 public long getLongValue() throws IOException { return delegate.getLongValue(); }
272
273 @Override
274 public NumberType getNumberType() throws IOException { return delegate.getNumberType(); }
275
276 @Override
277 public Number getNumberValue() throws IOException { return delegate.getNumberValue(); }
278
279 /*
280 /**********************************************************
281 /* Public API, access to token information, coercion/conversion
282 /**********************************************************
283 */
284
285 @Override public int getValueAsInt() throws IOException { return delegate.getValueAsInt(); }
286 @Override public int getValueAsInt(int defaultValue) throws IOException { return delegate.getValueAsInt(defaultValue); }
287 @Override public long getValueAsLong() throws IOException { return delegate.getValueAsLong(); }
288 @Override public long getValueAsLong(long defaultValue) throws IOException { return delegate.getValueAsLong(defaultValue); }
289 @Override public double getValueAsDouble() throws IOException { return delegate.getValueAsDouble(); }
290 @Override public double getValueAsDouble(double defaultValue) throws IOException { return delegate.getValueAsDouble(defaultValue); }
291 @Override public boolean getValueAsBoolean() throws IOException { return delegate.getValueAsBoolean(); }
292 @Override public boolean getValueAsBoolean(boolean defaultValue) throws IOException { return delegate.getValueAsBoolean(defaultValue); }
293 @Override public String getValueAsString() throws IOException { return delegate.getValueAsString(); }
294 @Override public String getValueAsString(String defaultValue) throws IOException { return delegate.getValueAsString(defaultValue); }
295
296 /*
297 /**********************************************************
298 /* Public API, access to token values, other
299 /**********************************************************
300 */
301
302 @Override public Object getEmbeddedObject() throws IOException { return delegate.getEmbeddedObject(); }
303 @Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException { return delegate.getBinaryValue(b64variant); }
304 @Override public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException { return delegate.readBinaryValue(b64variant, out); }
305 @Override public JsonLocation getTokenLocation() { return delegate.getTokenLocation(); }
306}