@Override
 public boolean hasTokenId(int id) {
   final JsonToken t = _currToken;
   if (t == null) {
     return (JsonTokenId.ID_NO_TOKEN == id);
   }
   return t.id() == id;
 }
 protected final double _testRawDeser(int reps, byte[] json, ObjectReader reader)
     throws IOException {
   long start = System.nanoTime();
   final JsonFactory f = reader.getFactory();
   while (--reps >= 0) {
     JsonParser p = f.createParser(new ByteArrayInputStream(json));
     JsonToken t;
     while ((t = p.nextToken()) != null) {
       if (t == JsonToken.VALUE_STRING) {
         p.getText();
       } else if (t.isNumeric()) {
         p.getNumberValue();
       }
       ;
     }
     p.close();
   }
   hash = f.hashCode();
   return _msecsFromNanos(System.nanoTime() - start);
 }
  /**
   * Parse a JSON data structure from content from a reader
   *
   * @param reader reader over a JSON content
   * @return a data structure of lists and maps
   */
  public Object parse(Reader reader) {
    Object content;

    JsonLexer lexer = new JsonLexer(reader);

    JsonToken token = lexer.nextToken();
    if (token.getType() == OPEN_CURLY) {
      content = parseObject(lexer);
    } else if (token.getType() == OPEN_BRACKET) {
      content = parseArray(lexer);
    } else {
      throw new JsonException(
          "A JSON payload should start with "
              + OPEN_CURLY.getLabel()
              + " or "
              + OPEN_BRACKET.getLabel()
              + ".\n"
              + "Instead, '"
              + token.getText()
              + "' was found "
              + "on line: "
              + token.getStartLine()
              + ", "
              + "column: "
              + token.getStartColumn());
    }

    return content;
  }
  /**
   * 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 ((_currToken != JsonToken.START_OBJECT) && (_currToken != 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;
        }
      }
    }
  }
  /** Method called when a new potentially included context is found. */
  protected final JsonToken _nextTokenWithBuffering(final TokenFilterContext buffRoot)
      throws IOException {
    main_loop:
    while (true) {
      JsonToken t = delegate.nextToken();
      if (t == null) { // is this even legal?
        return t;
      }
      TokenFilter f;

      // One simplification here: we know for a fact that the item filter is
      // neither null nor 'include all', for most cases; the only exception
      // being FIELD_NAME handling

      switch (t.id()) {
        case ID_START_ARRAY:
          f = _headContext.checkValue(_itemFilter);
          if (f == null) {
            delegate.skipChildren();
            continue main_loop;
          }
          if (f != TokenFilter.INCLUDE_ALL) {
            f = f.filterStartArray();
          }
          _itemFilter = f;
          if (f == TokenFilter.INCLUDE_ALL) {
            _headContext = _headContext.createChildArrayContext(f, true);
            return _nextBuffered(buffRoot);
          }
          _headContext = _headContext.createChildArrayContext(f, false);
          continue main_loop;

        case ID_START_OBJECT:
          f = _itemFilter;
          if (f == TokenFilter.INCLUDE_ALL) {
            _headContext = _headContext.createChildObjectContext(f, true);
            return t;
          }
          if (f == null) { // does this occur?
            delegate.skipChildren();
            continue main_loop;
          }
          // Otherwise still iffy, need to check
          f = _headContext.checkValue(f);
          if (f == null) {
            delegate.skipChildren();
            continue main_loop;
          }
          if (f != TokenFilter.INCLUDE_ALL) {
            f = f.filterStartObject();
          }
          _itemFilter = f;
          if (f == TokenFilter.INCLUDE_ALL) {
            _headContext = _headContext.createChildObjectContext(f, true);
            return _nextBuffered(buffRoot);
          }
          _headContext = _headContext.createChildObjectContext(f, false);
          continue main_loop;

        case ID_END_ARRAY:
        case ID_END_OBJECT:
          {
            // Unlike with other loops, here we know that content was NOT
            // included (won't get this far otherwise)
            f = _headContext.getFilter();
            if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
              f.filterFinishArray();
            }
            boolean gotEnd = (_headContext == buffRoot);
            boolean returnEnd = gotEnd && _headContext.isStartHandled();

            _headContext = _headContext.getParent();
            _itemFilter = _headContext.getFilter();

            if (returnEnd) {
              return t;
            }
            // Hmmh. Do we need both checks, or should above suffice?
            if (gotEnd || (_headContext == buffRoot)) {
              return null;
            }
          }
          continue main_loop;

        case ID_FIELD_NAME:
          {
            final String name = delegate.getCurrentName();
            f = _headContext.setFieldName(name);
            if (f == TokenFilter.INCLUDE_ALL) {
              _itemFilter = f;
              return _nextBuffered(buffRoot);
            }
            if (f == null) { // filter out the value
              delegate.nextToken();
              delegate.skipChildren();
              continue main_loop;
            }
            f = f.includeProperty(name);
            if (f == null) { // filter out the value
              delegate.nextToken();
              delegate.skipChildren();
              continue main_loop;
            }
            _itemFilter = f;
            if (f == TokenFilter.INCLUDE_ALL) {
              return _nextBuffered(buffRoot);
            }
          }
          continue main_loop;

        default: // scalar value
          f = _itemFilter;
          if (f == TokenFilter.INCLUDE_ALL) {
            return _nextBuffered(buffRoot);
          }
          if (f != null) {
            f = _headContext.checkValue(f);
            if ((f == TokenFilter.INCLUDE_ALL) || ((f != null) && f.includeValue(delegate))) {
              return _nextBuffered(buffRoot);
            }
          }
          // Otherwise not included (leaves must be explicitly included)
          continue main_loop;
      }
    }
  }
  /**
   * Offlined handling for cases where there was no buffered token to return, and the token read
   * next could not be returned as-is, at least not yet, but where we have not yet established that
   * buffering is needed.
   */
  protected final JsonToken _nextToken2() throws IOException {
    main_loop:
    while (true) {
      JsonToken t = delegate.nextToken();
      if (t == null) { // is this even legal?
        return (_currToken = t);
      }
      TokenFilter f;

      switch (t.id()) {
        case ID_START_ARRAY:
          f = _itemFilter;
          if (f == TokenFilter.INCLUDE_ALL) {
            _headContext = _headContext.createChildArrayContext(f, true);
            return (_currToken = t);
          }
          if (f == null) { // does this occur?
            delegate.skipChildren();
            continue main_loop;
          }
          // Otherwise still iffy, need to check
          f = _headContext.checkValue(f);
          if (f == null) {
            delegate.skipChildren();
            continue main_loop;
          }
          if (f != TokenFilter.INCLUDE_ALL) {
            f = f.filterStartArray();
          }
          _itemFilter = f;
          if (f == TokenFilter.INCLUDE_ALL) {
            _headContext = _headContext.createChildArrayContext(f, true);
            return (_currToken = t);
          }
          _headContext = _headContext.createChildArrayContext(f, false);
          // but if we didn't figure it out yet, need to buffer possible events
          if (_includePath) {
            t = _nextTokenWithBuffering(_headContext);
            if (t != null) {
              _currToken = t;
              return t;
            }
          }
          continue main_loop;

        case ID_START_OBJECT:
          f = _itemFilter;
          if (f == TokenFilter.INCLUDE_ALL) {
            _headContext = _headContext.createChildObjectContext(f, true);
            return (_currToken = t);
          }
          if (f == null) { // does this occur?
            delegate.skipChildren();
            continue main_loop;
          }
          // Otherwise still iffy, need to check
          f = _headContext.checkValue(f);
          if (f == null) {
            delegate.skipChildren();
            continue main_loop;
          }
          if (f != TokenFilter.INCLUDE_ALL) {
            f = f.filterStartObject();
          }
          _itemFilter = f;
          if (f == TokenFilter.INCLUDE_ALL) {
            _headContext = _headContext.createChildObjectContext(f, true);
            return (_currToken = t);
          }
          _headContext = _headContext.createChildObjectContext(f, false);
          if (_includePath) {
            t = _nextTokenWithBuffering(_headContext);
            if (t != null) {
              _currToken = t;
              return t;
            }
          }
          continue main_loop;

        case ID_END_ARRAY:
        case ID_END_OBJECT:
          {
            boolean returnEnd = _headContext.isStartHandled();
            f = _headContext.getFilter();
            if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
              f.filterFinishArray();
            }
            _headContext = _headContext.getParent();
            _itemFilter = _headContext.getFilter();
            if (returnEnd) {
              return (_currToken = t);
            }
          }
          continue main_loop;

        case ID_FIELD_NAME:
          {
            final String name = delegate.getCurrentName();
            f = _headContext.setFieldName(name);
            if (f == TokenFilter.INCLUDE_ALL) {
              _itemFilter = f;
              return (_currToken = t);
            }
            if (f == null) { // filter out the value
              delegate.nextToken();
              delegate.skipChildren();
              continue main_loop;
            }
            f = f.includeProperty(name);
            if (f == null) { // filter out the value
              delegate.nextToken();
              delegate.skipChildren();
              continue main_loop;
            }
            _itemFilter = f;
            if (f == TokenFilter.INCLUDE_ALL) {
              if (_includePath) {
                return (_currToken = t);
              }
              //                        if (_includeImmediateParent) { ...
              continue main_loop;
            }
            if (_includePath) {
              t = _nextTokenWithBuffering(_headContext);
              if (t != null) {
                _currToken = t;
                return t;
              }
            }
          }
          continue main_loop;

        default: // scalar value
          f = _itemFilter;
          if (f == TokenFilter.INCLUDE_ALL) {
            return (_currToken = t);
          }
          if (f != null) {
            f = _headContext.checkValue(f);
            if ((f == TokenFilter.INCLUDE_ALL) || ((f != null) && f.includeValue(delegate))) {
              return (_currToken = t);
            }
          }
          // Otherwise not included (leaves must be explicitly included)
          break;
      }
    }
  }
  @Override
  public JsonToken nextToken() throws IOException {
    // Anything buffered?
    TokenFilterContext ctxt = _exposedContext;

    if (ctxt != null) {
      while (true) {
        JsonToken t = ctxt.nextTokenToRead();
        if (t != null) {
          _currToken = t;
          return t;
        }
        // all done with buffered stuff?
        if (ctxt == _headContext) {
          _exposedContext = null;
          if (ctxt.inArray()) {
            t = delegate.getCurrentToken();
            // Is this guaranteed to work without further checks?
            //                        if (t != JsonToken.START_ARRAY) {
            _currToken = t;
            return t;
          }

          // Almost! Most likely still have the current token;
          // with the sole exception of
          /*
          t = delegate.getCurrentToken();
          if (t != JsonToken.FIELD_NAME) {
              _currToken = t;
              return t;
          }
          */
          break;
        }
        // If not, traverse down the context chain
        ctxt = _headContext.findChildOf(ctxt);
        _exposedContext = ctxt;
        if (ctxt == null) { // should never occur
          throw _constructError("Unexpected problem: chain of filtered context broken");
        }
      }
    }

    // If not, need to read more. If we got any:
    JsonToken t = delegate.nextToken();
    if (t == null) {
      // no strict need to close, since we have no state here
      return (_currToken = t);
    }

    // otherwise... to include or not?
    TokenFilter f;

    switch (t.id()) {
      case ID_START_ARRAY:
        f = _itemFilter;
        if (f == TokenFilter.INCLUDE_ALL) {
          _headContext = _headContext.createChildArrayContext(f, true);
          return (_currToken = t);
        }
        if (f == null) { // does this occur?
          delegate.skipChildren();
          break;
        }
        // Otherwise still iffy, need to check
        f = _headContext.checkValue(f);
        if (f == null) {
          delegate.skipChildren();
          break;
        }
        if (f != TokenFilter.INCLUDE_ALL) {
          f = f.filterStartArray();
        }
        _itemFilter = f;
        if (f == TokenFilter.INCLUDE_ALL) {
          _headContext = _headContext.createChildArrayContext(f, true);
          return (_currToken = t);
        }
        _headContext = _headContext.createChildArrayContext(f, false);

        // Also: only need buffering if parent path to be included
        if (_includePath) {
          t = _nextTokenWithBuffering(_headContext);
          if (t != null) {
            _currToken = t;
            return t;
          }
        }
        break;

      case ID_START_OBJECT:
        f = _itemFilter;
        if (f == TokenFilter.INCLUDE_ALL) {
          _headContext = _headContext.createChildObjectContext(f, true);
          return (_currToken = t);
        }
        if (f == null) { // does this occur?
          delegate.skipChildren();
          break;
        }
        // Otherwise still iffy, need to check
        f = _headContext.checkValue(f);
        if (f == null) {
          delegate.skipChildren();
          break;
        }
        if (f != TokenFilter.INCLUDE_ALL) {
          f = f.filterStartObject();
        }
        _itemFilter = f;
        if (f == TokenFilter.INCLUDE_ALL) {
          _headContext = _headContext.createChildObjectContext(f, true);
          return (_currToken = t);
        }
        _headContext = _headContext.createChildObjectContext(f, false);
        // Also: only need buffering if parent path to be included
        if (_includePath) {
          t = _nextTokenWithBuffering(_headContext);
          if (t != null) {
            _currToken = t;
            return t;
          }
        }
        // note: inclusion of surrounding Object handled separately via
        // FIELD_NAME
        break;

      case ID_END_ARRAY:
      case ID_END_OBJECT:
        {
          boolean returnEnd = _headContext.isStartHandled();
          f = _headContext.getFilter();
          if ((f != null) && (f != TokenFilter.INCLUDE_ALL)) {
            f.filterFinishArray();
          }
          _headContext = _headContext.getParent();
          _itemFilter = _headContext.getFilter();
          if (returnEnd) {
            return (_currToken = t);
          }
        }
        break;

      case ID_FIELD_NAME:
        {
          final String name = delegate.getCurrentName();
          // note: this will also set 'needToHandleName'
          f = _headContext.setFieldName(name);
          if (f == TokenFilter.INCLUDE_ALL) {
            _itemFilter = f;
            if (!_includePath) {
              // Minor twist here: if parent NOT included, may need to induce output of
              // surrounding START_OBJECT/END_OBJECT
              if (_includeImmediateParent && !_headContext.isStartHandled()) {
                t =
                    _headContext
                        .nextTokenToRead(); // returns START_OBJECT but also marks it handled
                _exposedContext = _headContext;
              }
            }
            return (_currToken = t);
          }
          if (f == null) {
            delegate.nextToken();
            delegate.skipChildren();
            break;
          }
          f = f.includeProperty(name);
          if (f == null) {
            delegate.nextToken();
            delegate.skipChildren();
            break;
          }
          _itemFilter = f;
          if (f == TokenFilter.INCLUDE_ALL) {
            if (_includePath) {
              return (_currToken = t);
            }
          }
          if (_includePath) {
            t = _nextTokenWithBuffering(_headContext);
            if (t != null) {
              _currToken = t;
              return t;
            }
          }
          break;
        }

      default: // scalar value
        f = _itemFilter;
        if (f == TokenFilter.INCLUDE_ALL) {
          return (_currToken = t);
        }
        if (f != null) {
          f = _headContext.checkValue(f);
          if ((f == TokenFilter.INCLUDE_ALL) || ((f != null) && f.includeValue(delegate))) {
            return (_currToken = t);
          }
        }
        // Otherwise not included (leaves must be explicitly included)
        break;
    }

    // We get here if token was not yet found; offlined handling
    return _nextToken2();
  }
 @Override
 public final int getCurrentTokenId() {
   final JsonToken t = _currToken;
   return (t == null) ? JsonTokenId.ID_NO_TOKEN : t.id();
 }
  /**
   * Parses an object from the lexer
   *
   * @param lexer the lexer
   * @return a Map representing a JSON object
   */
  private Map parseObject(JsonLexer lexer) {
    Map content = new HashMap();

    JsonToken previousToken = null;
    JsonToken currentToken = null;

    for (; ; ) {
      currentToken = lexer.nextToken();

      if (currentToken == null) {
        throw new JsonException(
            "Expected a String key on line: "
                + lexer.getReader().getLine()
                + ", "
                + "column: "
                + lexer.getReader().getColumn()
                + ".\n"
                + "But got an unterminated object.");
      }

      // expect a string key, or already a closing curly brace

      if (currentToken.getType() == CLOSE_CURLY) {
        return content;
      } else if (currentToken.getType() != STRING) {
        throw new JsonException(
            "Expected "
                + STRING.getLabel()
                + " key "
                + "on line: "
                + currentToken.getStartLine()
                + ", "
                + "column: "
                + currentToken.getStartColumn()
                + ".\n"
                + "But got '"
                + currentToken.getText()
                + "' instead.");
      }

      String mapKey = (String) currentToken.getValue();

      currentToken = lexer.nextToken();

      if (currentToken == null) {
        throw new JsonException(
            "Expected a "
                + COLON.getLabel()
                + " "
                + "on line: "
                + lexer.getReader().getLine()
                + ", "
                + "column: "
                + lexer.getReader().getColumn()
                + ".\n"
                + "But got an unterminated object.");
      }

      // expect a colon between the key and value pair

      if (currentToken.getType() != COLON) {
        throw new JsonException(
            "Expected "
                + COLON.getLabel()
                + " "
                + "on line: "
                + currentToken.getStartLine()
                + ", "
                + "column: "
                + currentToken.getStartColumn()
                + ".\n"
                + "But got '"
                + currentToken.getText()
                + "' instead.");
      }

      currentToken = lexer.nextToken();

      if (currentToken == null) {
        throw new JsonException(
            "Expected a value "
                + "on line: "
                + lexer.getReader().getLine()
                + ", "
                + "column: "
                + lexer.getReader().getColumn()
                + ".\n"
                + "But got an unterminated object.");
      }

      // value can be an object, an array, a number, string, boolean or null values

      if (currentToken.getType() == OPEN_CURLY) {
        content.put(mapKey, parseObject(lexer));
      } else if (currentToken.getType() == OPEN_BRACKET) {
        content.put(mapKey, parseArray(lexer));
      } else if (currentToken.getType().ordinal() >= NULL.ordinal()) {
        content.put(mapKey, currentToken.getValue());
      } else {
        throw new JsonException(
            "Expected a value, an array, or an object "
                + "on line: "
                + currentToken.getStartLine()
                + ", "
                + "column: "
                + currentToken.getStartColumn()
                + ".\n"
                + "But got '"
                + currentToken.getText()
                + "' instead.");
      }

      previousToken = currentToken;
      currentToken = lexer.nextToken();

      // premature end of the object

      if (currentToken == null) {
        throw new JsonException(
            "Expected "
                + CLOSE_CURLY.getLabel()
                + " or "
                + COMMA.getLabel()
                + " "
                + "on line: "
                + previousToken.getEndLine()
                + ", "
                + "column: "
                + previousToken.getEndColumn()
                + ".\n"
                + "But got an unterminated object.");
      }

      // Expect a comma for an upcoming key/value pair
      // or a closing curly brace for the end of the object
      if (currentToken.getType() == CLOSE_CURLY) {
        break;
      } else if (currentToken.getType() != COMMA) {
        throw new JsonException(
            "Expected a value or "
                + CLOSE_CURLY.getLabel()
                + " "
                + "on line: "
                + currentToken.getStartLine()
                + ", "
                + "column: "
                + currentToken.getStartColumn()
                + ".\n"
                + "But got '"
                + currentToken.getText()
                + "' instead.");
      }
    }

    return content;
  }
  /**
   * Parse an array from the lexer
   *
   * @param lexer the lexer
   * @return a list of JSON values
   */
  private List parseArray(JsonLexer lexer) {
    List content = new ArrayList();

    JsonToken currentToken;

    for (; ; ) {
      currentToken = lexer.nextToken();

      if (currentToken == null) {
        throw new JsonException(
            "Expected a value on line: "
                + lexer.getReader().getLine()
                + ", "
                + "column: "
                + lexer.getReader().getColumn()
                + ".\n"
                + "But got an unterminated array.");
      }

      if (currentToken.getType() == OPEN_CURLY) {
        content.add(parseObject(lexer));
      } else if (currentToken.getType() == OPEN_BRACKET) {
        content.add(parseArray(lexer));
      } else if (currentToken.getType().ordinal() >= NULL.ordinal()) {
        content.add(currentToken.getValue());
      } else if (currentToken.getType() == CLOSE_BRACKET) {
        return content;
      } else {
        throw new JsonException(
            "Expected a value, an array, or an object "
                + "on line: "
                + currentToken.getStartLine()
                + ", "
                + "column: "
                + currentToken.getStartColumn()
                + ".\n"
                + "But got '"
                + currentToken.getText()
                + "' instead.");
      }

      currentToken = lexer.nextToken();

      if (currentToken == null) {
        throw new JsonException(
            "Expected "
                + CLOSE_BRACKET.getLabel()
                + " "
                + "or "
                + COMMA.getLabel()
                + " "
                + "on line: "
                + lexer.getReader().getLine()
                + ", "
                + "column: "
                + lexer.getReader().getColumn()
                + ".\n"
                + "But got an unterminated array.");
      }

      // Expect a comma for an upcoming value
      // or a closing bracket for the end of the array
      if (currentToken.getType() == CLOSE_BRACKET) {
        break;
      } else if (currentToken.getType() != COMMA) {
        throw new JsonException(
            "Expected a value or "
                + CLOSE_BRACKET.getLabel()
                + " "
                + "on line: "
                + currentToken.getStartLine()
                + " "
                + "column: "
                + currentToken.getStartColumn()
                + ".\n"
                + "But got '"
                + currentToken.getText()
                + "' instead.");
      }
    }

    return content;
  }