blob: 3e22fbf16ff8cabbd66948dbcd44c67a45f276ce [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
Tatu Salorantab46e0372015-04-14 21:43:03 -070011import static com.fasterxml.jackson.core.JsonTokenId.*;
12
Tatu Salorantadfd69092015-04-09 22:29:34 -070013/**
14 * Specialized {@link JsonParserDelegate} that allows use of
15 * {@link TokenFilter} for outputting a subset of content that
16 * is visible to caller
17 *
18 * @since 2.6
19 */
20public class FilteringParserDelegate extends JsonParserDelegate
21{
22 /*
23 /**********************************************************
24 /* Configuration
25 /**********************************************************
26 */
27
28 /**
29 * Object consulted to determine whether to write parts of content generator
30 * is asked to write or not.
31 */
32 protected TokenFilter rootFilter;
33
34 /**
35 * Flag that determines whether filtering will continue after the first
36 * match is indicated or not: if `false`, output is based on just the first
37 * full match (returning {@link TokenFilter#INCLUDE_ALL}) and no more
38 * checks are made; if `true` then filtering will be applied as necessary
39 * until end of content.
40 */
41 protected boolean _allowMultipleMatches;
42
43 /**
44 * Flag that determines whether path leading up to included content should
45 * also be automatically included or not. If `false`, no path inclusion is
46 * done and only explicitly included entries are output; if `true` then
47 * path from main level down to match is also included as necessary.
48 */
49 protected boolean _includePath;
50
51 /*
52 /**********************************************************
53 /* State
54 /**********************************************************
55 */
56
57 /**
58 * Last token retrieved via {@link #nextToken}, if any.
59 * Null before the first call to <code>nextToken()</code>,
60 * as well as if token has been explicitly cleared
61 */
62 protected JsonToken _currToken;
63
64 /**
65 * Last cleared token, if any: that is, value that was in
66 * effect when {@link #clearCurrentToken} was called.
67 */
68 protected JsonToken _lastClearedToken;
69
70 /**
Cowtowncoder00900312015-04-14 16:02:33 -070071 * During traversal this is the actual "open" parse tree, which sometimes
72 * is the same as {@link #_exposedContext}, and at other times is ahead
73 * of it. Note that this context is never null.
Tatu Salorantadfd69092015-04-09 22:29:34 -070074 */
Cowtowncoder00900312015-04-14 16:02:33 -070075 protected TokenFilterContext _headContext;
Tatu Salorantadfd69092015-04-09 22:29:34 -070076
77 /**
Cowtowncoder00900312015-04-14 16:02:33 -070078 * In cases where {@link #_headContext} is "ahead" of context exposed to
79 * caller, this context points to what is currently exposed to caller.
80 * When the two are in sync, this context reference will be <code>null</code>.
81 */
82 protected TokenFilterContext _exposedContext;
Cowtowncoder9a797fb2015-04-14 16:12:12 -070083
Cowtowncoder00900312015-04-14 16:02:33 -070084 /**
Tatu Salorantadfd69092015-04-09 22:29:34 -070085 * State that applies to the item within container, used where applicable.
86 * Specifically used to pass inclusion state between property name and
87 * property, and also used for array elements.
88 */
89 protected TokenFilter _itemFilter;
90
91 /**
92 * Number of tokens for which {@link TokenFilter#INCLUDE_ALL}
Tatu Saloranta5a5d1192015-04-13 23:05:07 -070093 * has been returned.
Tatu Salorantadfd69092015-04-09 22:29:34 -070094 */
95 protected int _matchCount;
96
97 /*
98 /**********************************************************
99 /* Construction, initialization
100 /**********************************************************
101 */
102
103 public FilteringParserDelegate(JsonParser p, TokenFilter f,
104 boolean includePath, boolean allowMultipleMatches)
105 {
106 super(p);
107 rootFilter = f;
108 // and this is the currently active filter for root values
109 _itemFilter = f;
Cowtowncoder00900312015-04-14 16:02:33 -0700110 _headContext = TokenFilterContext.createRootContext(f);
Tatu Salorantadfd69092015-04-09 22:29:34 -0700111 _includePath = includePath;
112 _allowMultipleMatches = allowMultipleMatches;
113 }
114
115 /*
116 /**********************************************************
117 /* Extended API
118 /**********************************************************
119 */
120
121 public TokenFilter getFilter() { return rootFilter; }
122
123 /**
124 * Accessor for finding number of matches, where specific token and sub-tree
125 * starting (if structured type) are passed.
126 */
127 public int getMatchCount() {
128 return _matchCount;
129 }
130
131 /*
132 /**********************************************************
133 /* Public API, token accessors
134 /**********************************************************
135 */
136
137 @Override public JsonToken getCurrentToken() { return _currToken; }
138
139 @Override public final int getCurrentTokenId() {
140 final JsonToken t = _currToken;
141 return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id();
142 }
143
144 @Override public boolean hasCurrentToken() { return _currToken != null; }
145 @Override public boolean hasTokenId(int id) {
146 final JsonToken t = _currToken;
147 if (t == null) {
148 return (JsonTokenId.ID_NO_TOKEN == id);
149 }
150 return t.id() == id;
151 }
152
153 @Override public final boolean hasToken(JsonToken t) {
154 return (_currToken == t);
155 }
156
157 @Override public boolean isExpectedStartArrayToken() { return _currToken == JsonToken.START_ARRAY; }
158 @Override public boolean isExpectedStartObjectToken() { return _currToken == JsonToken.START_OBJECT; }
159
160 @Override public JsonLocation getCurrentLocation() { return delegate.getCurrentLocation(); }
Tatu Salorantadfd69092015-04-09 22:29:34 -0700161
Cowtowncoder00900312015-04-14 16:02:33 -0700162 @Override
163 public JsonStreamContext getParsingContext() {
164 return _filterContext();
165 }
Tatu Salorantadfd69092015-04-09 22:29:34 -0700166
Cowtowncoder00900312015-04-14 16:02:33 -0700167 // !!! TODO: Verify it works as expected: copied from standard JSON parser impl
168 @Override
169 public String getCurrentName() throws IOException {
170 JsonStreamContext ctxt = _filterContext();
171 if (_currToken == JsonToken.START_OBJECT || _currToken == JsonToken.START_ARRAY) {
172 JsonStreamContext parent = ctxt.getParent();
173 return (parent == null) ? null : parent.getCurrentName();
174 }
175 return ctxt.getCurrentName();
176 }
177
Tatu Salorantadfd69092015-04-09 22:29:34 -0700178 /*
179 /**********************************************************
180 /* Public API, token state overrides
181 /**********************************************************
182 */
183
184 @Override
185 public void clearCurrentToken() {
186 if (_currToken != null) {
187 _lastClearedToken = _currToken;
188 _currToken = null;
189 }
190 }
191
192 @Override
193 public JsonToken getLastClearedToken() { return _lastClearedToken; }
194
Tatu Salorantadfd69092015-04-09 22:29:34 -0700195 @Override
Cowtowncoder00900312015-04-14 16:02:33 -0700196 public void overrideCurrentName(String name) {
197 /* 14-Apr-2015, tatu: Not sure whether this can be supported, and if so,
198 * what to do with it... Delegation won't work for sure, so let's for
199 * now throw an exception
200 */
201 throw new UnsupportedOperationException("Can not currently override name during filtering read");
202 }
Tatu Salorantadfd69092015-04-09 22:29:34 -0700203
204 /*
205 /**********************************************************
206 /* Public API, traversal
207 /**********************************************************
208 */
209
Cowtowncoder00900312015-04-14 16:02:33 -0700210 @Override
211 public JsonToken nextToken() throws IOException
212 {
Cowtowncoder9a797fb2015-04-14 16:12:12 -0700213 // Anything buffered?
Cowtowncoder37d0d6e2015-04-14 19:48:10 -0700214 TokenFilterContext ctxt = _exposedContext;
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700215
Cowtowncoder37d0d6e2015-04-14 19:48:10 -0700216 if (ctxt != null) {
217 while (true) {
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700218 JsonToken t = _exposedContext.nextTokenToRead();
Cowtowncoder37d0d6e2015-04-14 19:48:10 -0700219 if (t != null) {
220 _currToken = t;
221 return t;
222 }
223 // all done with buffered stuff?
224 if (ctxt == _headContext) {
225 _exposedContext = null;
226 break;
227 }
228 // If not, traverse down the context chain
229 ctxt = _exposedContext.findChildOf(_exposedContext);
230 _exposedContext = ctxt;
231 if (ctxt == null) { // should never occur
232 throw _constructError("Unexpected problem: chain of filtered context broken");
233 }
234 }
235 }
236
Tatu Salorantab46e0372015-04-14 21:43:03 -0700237 // If not, need to read more. If we got any:
Cowtowncoder37d0d6e2015-04-14 19:48:10 -0700238 JsonToken t = delegate.nextToken();
239 if (t == null) {
Tatu Salorantab46e0372015-04-14 21:43:03 -0700240 // no strict need to close, since we have no state here
241 return (_currToken = t);
Cowtowncoder9a797fb2015-04-14 16:12:12 -0700242 }
Tatu Salorantace077d42015-04-14 20:48:23 -0700243
Tatu Salorantab46e0372015-04-14 21:43:03 -0700244 // otherwise... to include or not?
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700245 TokenFilter f;
246
247 switch (t.id()) {
Tatu Salorantab46e0372015-04-14 21:43:03 -0700248 case ID_START_ARRAY:
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700249 f = _itemFilter;
250 if (f == TokenFilter.INCLUDE_ALL) {
251 _headContext = _headContext.createChildArrayContext(f, true);
252 return (_currToken = t);
253 }
254 if (f == null) { // does this occur?
Tatu Salorantab46e0372015-04-14 21:43:03 -0700255 delegate.skipChildren();
256 break;
257 }
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700258 // Otherwise still iffy, need to check
259 f = _headContext.checkValue(f);
260 if (f == null) {
261 delegate.skipChildren();
262 break;
263 }
264 if (f != TokenFilter.INCLUDE_ALL) {
265 f = f.filterStartArray();
266 }
267 _itemFilter = f;
268 _headContext = _headContext.createChildArrayContext(f, true);
269 if (f == TokenFilter.INCLUDE_ALL) {
Tatu Salorantab46e0372015-04-14 21:43:03 -0700270 return (_currToken = t);
271 }
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700272 // but if we didn't figure it out yet, need to buffer possible events
273 return _nextTokenWithBuffering(_headContext);
Tatu Salorantab46e0372015-04-14 21:43:03 -0700274
275 case ID_START_OBJECT:
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700276 f = _itemFilter;
277 if (f == TokenFilter.INCLUDE_ALL) {
278 _headContext = _headContext.createChildObjectContext(f, true);
279 return (_currToken = t);
280 }
281 if (f == null) { // does this occur?
Tatu Salorantab46e0372015-04-14 21:43:03 -0700282 delegate.skipChildren();
283 break;
284 }
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700285 // Otherwise still iffy, need to check
286 f = _headContext.checkValue(f);
287 if (f == null) {
288 delegate.skipChildren();
289 break;
290 }
291 if (f != TokenFilter.INCLUDE_ALL) {
292 f = f.filterStartObject();
293 }
294 _itemFilter = f;
295 _headContext = _headContext.createChildObjectContext(f, true);
296 if (f == TokenFilter.INCLUDE_ALL) {
Tatu Salorantab46e0372015-04-14 21:43:03 -0700297 return (_currToken = t);
298 }
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700299 // but if we didn't figure it out yet, need to buffer possible events
300 return _nextTokenWithBuffering(_headContext);
Tatu Salorantab46e0372015-04-14 21:43:03 -0700301
302 case ID_END_ARRAY:
303 case ID_END_OBJECT:
304 {
305 boolean returnEnd = _headContext.isStartHandled();
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700306 f = _headContext.getFilter();
Tatu Salorantab46e0372015-04-14 21:43:03 -0700307 if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
308 f.filterFinishArray();
309 }
310 _headContext = _headContext.getParent();
311 _itemFilter = _headContext.getFilter();
312 if (returnEnd) {
313 return (_currToken = t);
314 }
315 }
316 break;
317
318 case ID_FIELD_NAME:
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700319 {
320 final String name = delegate.getCurrentName();
321 f = _headContext.setFieldName(name);
322 if (f == TokenFilter.INCLUDE_ALL) {
323 _itemFilter = f;
324 return (_currToken = t);
325 }
326 if (f == null) { // filter out the value
327 delegate.nextToken();
328 delegate.skipChildren();
329 break;
330 }
331 f = f.includeProperty(name);
332 if (f == null) { // filter out the value
333 delegate.nextToken();
334 delegate.skipChildren();
335 break;
336 }
337 if (f == TokenFilter.INCLUDE_ALL) {
338 _itemFilter = f;
339 return (_currToken = t);
340 }
341 // !!! TODO: still not decided if to include, so...
342
343 _itemFilter = f;
344 }
345 break;
Tatu Salorantab46e0372015-04-14 21:43:03 -0700346
347 default: // scalar value
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700348 if (_itemFilter == TokenFilter.INCLUDE_ALL) {
349 return (_currToken = t);
350 }
351 // Otherwise not included (leaves must be explicitly included)
352 break;
Tatu Salorantab46e0372015-04-14 21:43:03 -0700353 }
354
355 // We get here if token was not yet found; offlined handling
356 return _nextToken2();
357 }
358
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700359 /**
360 * Offlined handling for cases where there was no buffered token to
361 * return, and the token read next could not be returned as-is,
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700362 * at least not yet, but where we have not yet established that
363 * buffering is needed.
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700364 */
Tatu Salorantab46e0372015-04-14 21:43:03 -0700365 protected final JsonToken _nextToken2() throws IOException
366 {
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700367 main_loop:
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700368 while (true) {
369 JsonToken t = delegate.nextToken();
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700370
371 if (t == null) { // is this even legal?
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700372 return (_currToken = t);
373 }
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700374 TokenFilter f;
375
376 switch (t.id()) {
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700377 case ID_START_ARRAY:
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700378 f = _itemFilter;
379 if (f == TokenFilter.INCLUDE_ALL) {
380 _headContext = _headContext.createChildArrayContext(f, true);
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700381 return (_currToken = t);
382 }
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700383 if (f == null) { // does this occur?
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700384 delegate.skipChildren();
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700385 continue main_loop;
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700386 }
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700387 // Otherwise still iffy, need to check
388 f = _headContext.checkValue(f);
389 if (f == null) {
390 delegate.skipChildren();
391 continue main_loop;
392 }
393 if (f != TokenFilter.INCLUDE_ALL) {
394 f = f.filterStartArray();
395 }
396 _itemFilter = f;
397 _headContext = _headContext.createChildArrayContext(f, true);
398 if (f == TokenFilter.INCLUDE_ALL) {
399 return (_currToken = t);
400 }
401 // but if we didn't figure it out yet, need to buffer possible events
402 return _nextTokenWithBuffering(_headContext);
403
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700404 case ID_START_OBJECT:
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700405 f = _itemFilter;
406 if (f == TokenFilter.INCLUDE_ALL) {
407 _headContext = _headContext.createChildObjectContext(f, true);
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700408 return (_currToken = t);
409 }
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700410 if (f == null) { // does this occur?
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700411 delegate.skipChildren();
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700412 continue main_loop;
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700413 }
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700414 // Otherwise still iffy, need to check
415 f = _headContext.checkValue(f);
416 if (f == null) {
417 delegate.skipChildren();
418 continue main_loop;
419 }
420 if (f != TokenFilter.INCLUDE_ALL) {
421 f = f.filterStartObject();
422 }
423 _itemFilter = f;
424 _headContext = _headContext.createChildObjectContext(f, true);
425 if (f == TokenFilter.INCLUDE_ALL) {
426 return (_currToken = t);
427 }
428 // but if we didn't figure it out yet, need to buffer possible events
429 return _nextTokenWithBuffering(_headContext);
430
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700431 case ID_END_ARRAY:
432 case ID_END_OBJECT:
433 {
434 boolean returnEnd = _headContext.isStartHandled();
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700435 f = _headContext.getFilter();
436 if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
437 f.filterFinishArray();
438 }
439 _headContext = _headContext.getParent();
440 _itemFilter = _headContext.getFilter();
441 if (returnEnd) {
442 return (_currToken = t);
443 }
444 }
445 continue main_loop;
446
447 case ID_FIELD_NAME:
448 {
449 final String name = delegate.getCurrentName();
450 f = _headContext.setFieldName(name);
451 if (f == TokenFilter.INCLUDE_ALL) {
452 _itemFilter = f;
453 return (_currToken = t);
454 }
455 if (f == null) { // filter out the value
456 delegate.nextToken();
457 delegate.skipChildren();
458 break;
459 }
460 f = f.includeProperty(name);
461 if (f == null) { // filter out the value
462 delegate.nextToken();
463 delegate.skipChildren();
464 break;
465 }
466 if (f == TokenFilter.INCLUDE_ALL) {
467 _itemFilter = f;
468 return (_currToken = t);
469 }
470 // !!! TODO: still not decided if to include, so...
471
472 _itemFilter = f;
473 }
474 continue main_loop;
475
476 default: // scalar value
477 if (_itemFilter == TokenFilter.INCLUDE_ALL) {
478 return (_currToken = t);
479 }
480 // Otherwise not included (leaves must be explicitly included)
481 continue main_loop;
482 }
483 }
484 }
485
486 /**
487 * Method called when a new potentially included context is found.
488 */
489 protected final JsonToken _nextTokenWithBuffering(TokenFilterContext buffRoot) throws IOException
490 {
491 _exposedContext = _headContext;
492
493 while (true) {
494 JsonToken t = delegate.nextToken();
495
496 if (t == null) { // is this even legal?
497 return (_currToken = t);
498 }
499 TokenFilter f;
500
501 switch (t.id()) {
502 case ID_START_ARRAY:
503 f = _itemFilter;
504 if (f == TokenFilter.INCLUDE_ALL) {
505 _headContext = _headContext.createChildArrayContext(f, true);
506 return (_currToken = t);
507 }
508 if (f == null) { // does this occur?
509 delegate.skipChildren();
510 break;
511 }
512 // Otherwise still iffy, need to check
513 f = _headContext.checkValue(f);
514 if (f == null) {
515 delegate.skipChildren();
516 break;
517 }
518 if (f != TokenFilter.INCLUDE_ALL) {
519 f = f.filterStartArray();
520 }
521 _itemFilter = f;
522 _headContext = _headContext.createChildArrayContext(f, true);
523 if (f == TokenFilter.INCLUDE_ALL) {
524 return (_currToken = t);
525 }
526 break;
527
528 case ID_START_OBJECT:
529 f = _itemFilter;
530 if (f == TokenFilter.INCLUDE_ALL) {
531 _headContext = _headContext.createChildObjectContext(f, true);
532 return (_currToken = t);
533 }
534 if (f == null) { // does this occur?
535 delegate.skipChildren();
536 break;
537 }
538 // Otherwise still iffy, need to check
539 f = _headContext.checkValue(f);
540 if (f == null) {
541 delegate.skipChildren();
542 break;
543 }
544 if (f != TokenFilter.INCLUDE_ALL) {
545 f = f.filterStartObject();
546 }
547 _itemFilter = f;
548 _headContext = _headContext.createChildObjectContext(f, true);
549 if (f == TokenFilter.INCLUDE_ALL) {
550 return (_currToken = t);
551 }
552 break;
553
554 case ID_END_ARRAY:
555 case ID_END_OBJECT:
556 {
557 boolean returnEnd = _headContext.isStartHandled();
558 f = _headContext.getFilter();
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700559 if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
560 f.filterFinishArray();
561 }
562 _headContext = _headContext.getParent();
563 _itemFilter = _headContext.getFilter();
564 if (returnEnd) {
565 return (_currToken = t);
566 }
567 }
568 break;
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700569
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700570 case ID_FIELD_NAME:
571 {
572 final String name = delegate.getCurrentName();
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700573 f = _headContext.setFieldName(name);
574 if (f == TokenFilter.INCLUDE_ALL) {
575 _itemFilter = f;
576 return (_currToken = t);
577 }
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700578 if (f == null) { // filter out the value
579 delegate.nextToken();
580 delegate.skipChildren();
581 break;
582 }
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700583 f = f.includeProperty(name);
584 if (f == null) { // filter out the value
585 delegate.nextToken();
586 delegate.skipChildren();
587 break;
588 }
589 if (f == TokenFilter.INCLUDE_ALL) {
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700590 _itemFilter = f;
591 return (_currToken = t);
592 }
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700593 // !!! TODO: still not decided if to include, so...
594
Tatu Saloranta404aebc2015-04-14 22:47:07 -0700595 _itemFilter = f;
596 }
597 break;
598
599 default: // scalar value
600 if (_itemFilter == TokenFilter.INCLUDE_ALL) {
601 return (_currToken = t);
602 }
603 // Otherwise not included (leaves must be explicitly included)
604 break;
605 }
606 }
Tatu Salorantab1ac0572015-04-15 22:35:00 -0700607 }
Tatu Salorantab46e0372015-04-14 21:43:03 -0700608
Tatu Salorantadfd69092015-04-09 22:29:34 -0700609 @Override
610 public JsonToken nextValue() throws IOException {
611 // Re-implemented same as ParserMinimalBase:
612 JsonToken t = nextToken();
613 if (t == JsonToken.FIELD_NAME) {
614 t = nextToken();
615 }
616 return t;
617 }
618
619 /**
620 * Need to override, re-implement similar to how method defined in
621 * {@link com.fasterxml.jackson.core.base.ParserMinimalBase}, to keep
622 * state correct here.
623 */
624 @Override
625 public JsonParser skipChildren() throws IOException
626 {
Cowtowncoder00900312015-04-14 16:02:33 -0700627 if ((_currToken != JsonToken.START_OBJECT)
628 && (_currToken != JsonToken.START_ARRAY)) {
Tatu Salorantadfd69092015-04-09 22:29:34 -0700629 return this;
630 }
631 int open = 1;
632
633 // Since proper matching of start/end markers is handled
634 // by nextToken(), we'll just count nesting levels here
635 while (true) {
636 JsonToken t = nextToken();
637 if (t == null) { // not ideal but for now, just return
638 return this;
639 }
640 if (t.isStructStart()) {
641 ++open;
642 } else if (t.isStructEnd()) {
643 if (--open == 0) {
644 return this;
645 }
646 }
647 }
648 }
649
650 /*
651 /**********************************************************
652 /* Public API, access to token information, text
653 /**********************************************************
654 */
655
656 @Override public String getText() throws IOException { return delegate.getText(); }
657 @Override public boolean hasTextCharacters() { return delegate.hasTextCharacters(); }
658 @Override public char[] getTextCharacters() throws IOException { return delegate.getTextCharacters(); }
659 @Override public int getTextLength() throws IOException { return delegate.getTextLength(); }
660 @Override public int getTextOffset() throws IOException { return delegate.getTextOffset(); }
661
662 /*
663 /**********************************************************
664 /* Public API, access to token information, numeric
665 /**********************************************************
666 */
667
668 @Override
669 public BigInteger getBigIntegerValue() throws IOException { return delegate.getBigIntegerValue(); }
670
671 @Override
672 public boolean getBooleanValue() throws IOException { return delegate.getBooleanValue(); }
673
674 @Override
675 public byte getByteValue() throws IOException { return delegate.getByteValue(); }
676
677 @Override
678 public short getShortValue() throws IOException { return delegate.getShortValue(); }
679
680 @Override
681 public BigDecimal getDecimalValue() throws IOException { return delegate.getDecimalValue(); }
682
683 @Override
684 public double getDoubleValue() throws IOException { return delegate.getDoubleValue(); }
685
686 @Override
687 public float getFloatValue() throws IOException { return delegate.getFloatValue(); }
688
689 @Override
690 public int getIntValue() throws IOException { return delegate.getIntValue(); }
691
692 @Override
693 public long getLongValue() throws IOException { return delegate.getLongValue(); }
694
695 @Override
696 public NumberType getNumberType() throws IOException { return delegate.getNumberType(); }
697
698 @Override
699 public Number getNumberValue() throws IOException { return delegate.getNumberValue(); }
700
701 /*
702 /**********************************************************
703 /* Public API, access to token information, coercion/conversion
704 /**********************************************************
705 */
706
707 @Override public int getValueAsInt() throws IOException { return delegate.getValueAsInt(); }
708 @Override public int getValueAsInt(int defaultValue) throws IOException { return delegate.getValueAsInt(defaultValue); }
709 @Override public long getValueAsLong() throws IOException { return delegate.getValueAsLong(); }
710 @Override public long getValueAsLong(long defaultValue) throws IOException { return delegate.getValueAsLong(defaultValue); }
711 @Override public double getValueAsDouble() throws IOException { return delegate.getValueAsDouble(); }
712 @Override public double getValueAsDouble(double defaultValue) throws IOException { return delegate.getValueAsDouble(defaultValue); }
713 @Override public boolean getValueAsBoolean() throws IOException { return delegate.getValueAsBoolean(); }
714 @Override public boolean getValueAsBoolean(boolean defaultValue) throws IOException { return delegate.getValueAsBoolean(defaultValue); }
715 @Override public String getValueAsString() throws IOException { return delegate.getValueAsString(); }
716 @Override public String getValueAsString(String defaultValue) throws IOException { return delegate.getValueAsString(defaultValue); }
717
718 /*
719 /**********************************************************
720 /* Public API, access to token values, other
721 /**********************************************************
722 */
723
724 @Override public Object getEmbeddedObject() throws IOException { return delegate.getEmbeddedObject(); }
725 @Override public byte[] getBinaryValue(Base64Variant b64variant) throws IOException { return delegate.getBinaryValue(b64variant); }
726 @Override public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException { return delegate.readBinaryValue(b64variant, out); }
727 @Override public JsonLocation getTokenLocation() { return delegate.getTokenLocation(); }
Cowtowncoder00900312015-04-14 16:02:33 -0700728
729 /*
730 /**********************************************************
731 /* Internal helper methods
732 /**********************************************************
733 */
734
735 protected JsonStreamContext _filterContext() {
736 if (_exposedContext != null) {
737 return _exposedContext;
738 }
739 return _headContext;
740 }
741
Tatu Salorantadfd69092015-04-09 22:29:34 -0700742}