package com.fasterxml.jackson.core.util;

import java.io.IOException;
import java.util.*;

import com.fasterxml.jackson.core.*;

Helper class that can be used to sequence multiple physical JsonParsers to create a single logical sequence of tokens, as a single JsonParser.

Fairly simple use of JsonParserDelegate: only need to override nextToken to handle transition

/** * Helper class that can be used to sequence multiple physical * {@link JsonParser}s to create a single logical sequence of * tokens, as a single {@link JsonParser}. *<p> * Fairly simple use of {@link JsonParserDelegate}: only need * to override {@link #nextToken} to handle transition */
public class JsonParserSequence extends JsonParserDelegate {
Parsers other than the first one (which is initially assigned as delegate)
/** * Parsers other than the first one (which is initially assigned * as delegate) */
protected final JsonParser[] _parsers;
Configuration that determines whether state of parsers is first verified to see if parser already points to a token (that is, JsonParser.hasCurrentToken() returns true), and if so that token is first return before JsonParser.nextToken is called. If enabled, this check is made; if disabled, no check is made and JsonParser.nextToken is always called for all parsers.

Default setting is false (for backwards-compatibility) so that possible existing token is not considered for parsers.

Since:2.8
/** * Configuration that determines whether state of parsers is first verified * to see if parser already points to a token (that is, * {@link JsonParser#hasCurrentToken()} returns <code>true</code>), and if so * that token is first return before {@link JsonParser#nextToken} is called. * If enabled, this check is made; if disabled, no check is made and * {@link JsonParser#nextToken} is always called for all parsers. *<p> * Default setting is <code>false</code> (for backwards-compatibility) * so that possible existing token is not considered for parsers. * * @since 2.8 */
protected final boolean _checkForExistingToken;
Index of the next parser in _parsers.
/** * Index of the next parser in {@link #_parsers}. */
protected int _nextParserIndex;
Flag used to indicate that `JsonParser.nextToken()` should not be called, due to parser already pointing to a token.
Since:2.8
/** * Flag used to indicate that `JsonParser.nextToken()` should not be called, * due to parser already pointing to a token. * * @since 2.8 */
protected boolean _hasToken; /* ******************************************************* * Construction ******************************************************* */ @Deprecated // since 2.8 protected JsonParserSequence(JsonParser[] parsers) { this(false, parsers); }
Since:2.8
/** * @since 2.8 */
protected JsonParserSequence(boolean checkForExistingToken, JsonParser[] parsers) { super(parsers[0]); _checkForExistingToken = checkForExistingToken; _hasToken = checkForExistingToken && delegate.hasCurrentToken(); _parsers = parsers; _nextParserIndex = 1; }
Method that will construct a parser (possibly a sequence) that contains all given sub-parsers. All parsers given are checked to see if they are sequences: and if so, they will be "flattened", that is, contained parsers are directly added in a new sequence instead of adding sequences within sequences. This is done to minimize delegation depth, ideally only having just a single level of delegation.
/** * Method that will construct a parser (possibly a sequence) that * contains all given sub-parsers. * All parsers given are checked to see if they are sequences: and * if so, they will be "flattened", that is, contained parsers are * directly added in a new sequence instead of adding sequences * within sequences. This is done to minimize delegation depth, * ideally only having just a single level of delegation. */
public static JsonParserSequence createFlattened(boolean checkForExistingToken, JsonParser first, JsonParser second) { if (!(first instanceof JsonParserSequence || second instanceof JsonParserSequence)) { return new JsonParserSequence(checkForExistingToken, new JsonParser[] { first, second }); } ArrayList<JsonParser> p = new ArrayList<JsonParser>(); if (first instanceof JsonParserSequence) { ((JsonParserSequence) first).addFlattenedActiveParsers(p); } else { p.add(first); } if (second instanceof JsonParserSequence) { ((JsonParserSequence) second).addFlattenedActiveParsers(p); } else { p.add(second); } return new JsonParserSequence(checkForExistingToken, p.toArray(new JsonParser[p.size()])); }
Deprecated:Since 2.8 use createFlattened(boolean, JsonParser, JsonParser) instead
/** * @deprecated Since 2.8 use {@link #createFlattened(boolean, JsonParser, JsonParser)} * instead */
@Deprecated // since 2.8 public static JsonParserSequence createFlattened(JsonParser first, JsonParser second) { return createFlattened(false, first, second); } @SuppressWarnings("resource") protected void addFlattenedActiveParsers(List<JsonParser> listToAddIn) { for (int i = _nextParserIndex-1, len = _parsers.length; i < len; ++i) { JsonParser p = _parsers[i]; if (p instanceof JsonParserSequence) { ((JsonParserSequence) p).addFlattenedActiveParsers(listToAddIn); } else { listToAddIn.add(p); } } } /* /******************************************************* /* Overridden methods, needed: cases where default /* delegation does not work /******************************************************* */ @Override public void close() throws IOException { do { delegate.close(); } while (switchToNext()); } @Override public JsonToken nextToken() throws IOException { if (delegate == null) { return null; } if (_hasToken) { _hasToken = false; return delegate.currentToken(); } JsonToken t = delegate.nextToken(); if (t == null) { return switchAndReturnNext(); } return t; }
Need to override, re-implement similar to how method defined in ParserMinimalBase, to keep state correct here.
/** * Need to override, re-implement similar to how method defined in * {@link com.fasterxml.jackson.core.base.ParserMinimalBase}, to keep * state correct here. */
@Override public JsonParser skipChildren() throws IOException { if ((delegate.currentToken() != JsonToken.START_OBJECT) && (delegate.currentToken() != JsonToken.START_ARRAY)) { return this; } int open = 1; // Since proper matching of start/end markers is handled // by nextToken(), we'll just count nesting levels here while (true) { JsonToken t = nextToken(); if (t == null) { // not ideal but for now, just return return this; } if (t.isStructStart()) { ++open; } else if (t.isStructEnd()) { if (--open == 0) { return this; } } } } /* /******************************************************* /* Additional extended API /******************************************************* */
Method that is most useful for debugging or testing; returns actual number of underlying parsers sequence was constructed with (nor just ones remaining active)
/** * Method that is most useful for debugging or testing; * returns actual number of underlying parsers sequence * was constructed with (nor just ones remaining active) */
public int containedParsersCount() { return _parsers.length; } /* /******************************************************* /* Helper methods /******************************************************* */
Method that will switch active delegate parser from the current one to the next parser in sequence, if there is another parser left: if so, the next parser will become the active delegate parser.
Returns:True if switch succeeded; false otherwise
Since:2.8
/** * Method that will switch active delegate parser from the current one * to the next parser in sequence, if there is another parser left: * if so, the next parser will become the active delegate parser. * * @return True if switch succeeded; false otherwise * * @since 2.8 */
protected boolean switchToNext() { if (_nextParserIndex < _parsers.length) { delegate = _parsers[_nextParserIndex++]; return true; } return false; } protected JsonToken switchAndReturnNext() throws IOException { while (_nextParserIndex < _parsers.length) { delegate = _parsers[_nextParserIndex++]; if (_checkForExistingToken && delegate.hasCurrentToken()) { return delegate.getCurrentToken(); } JsonToken t = delegate.nextToken(); if (t != null) { return t; } } return null; } }