openrtb-core/src/main/java/com/google/openrtb/json/AbstractOpenRtbJsonReader.java
protected final <EB extends ExtendableBuilder<?, EB>>
  void readExtensions(EB msg, JsonParser par) throws IOException {
    @SuppressWarnings("unchecked")
    Set<OpenRtbJsonExtReader<EB>> extReaders = factory.getReaders((Class<EB>) msg.getClass());
    if (extReaders.isEmpty()) {
      par.skipChildren();
      return;
    }

    startObject(par);
    JsonToken tokLast = par.getCurrentToken();
    JsonLocation locLast = par.getCurrentLocation();

    while (true) {
      boolean extRead = false;
      for (OpenRtbJsonExtReader<EB> extReader : extReaders) {
        if (extReader.filter(par)) {
          extReader.read(msg, par);
          JsonToken tokNew = par.getCurrentToken();
          JsonLocation locNew = par.getCurrentLocation();
          boolean advanced = tokNew != tokLast || !locNew.equals(locLast);
          extRead |= advanced;

          if (!endObject(par)) {
            return;
          } else if (advanced && par.getCurrentToken() != JsonToken.FIELD_NAME) {
            tokLast = par.nextToken();
            locLast = par.getCurrentLocation();
          } else {
            tokLast = tokNew;
            locLast = locNew;
          }
        }
      }

      if (!endObject(par)) {
        // Can't rely on this exit condition inside the for loop because no readers may filter.
        return;
      }

      if (!extRead) {
        // No field was consumed by any reader, so we need to skip the field to make progress.
        if (logger.isDebugEnabled()) {
          logger.debug("Extension field not consumed by any reader, skipping: {} @{}:{}",
              par.getCurrentName(), locLast.getLineNr(), locLast.getCharOffset());
        }
        par.nextToken();
        par.skipChildren();
        tokLast = par.nextToken();
        locLast = par.getCurrentLocation();
      }
      // Else loop, try all readers again
    }
  }
protected final <EB extends ExtendableBuilder<?, EB>>
  void readExtensions(EB msg, JsonParser par) throws IOException {
    @SuppressWarnings("unchecked")
    Set<OpenRtbJsonExtReader<EB>> extReaders = factory.getReaders((Class<EB>) msg.getClass());
    if (extReaders.isEmpty()) {
      par.skipChildren();
      return;
    }

    startObject(par);
    JsonToken tokLast = par.getCurrentToken();
    JsonLocation locLast = par.getCurrentLocation();

    while (true) {
      boolean extRead = false;
      for (OpenRtbJsonExtReader<EB> extReader : extReaders) {
        if (extReader.filter(par)) {
          extReader.read(msg, par);
          JsonToken tokNew = par.getCurrentToken();
          JsonLocation locNew = par.getCurrentLocation();
          boolean advanced = tokNew != tokLast || !locNew.equals(locLast);
          extRead |= advanced;

          if (!endObject(par)) {
            return;
          } else if (advanced && par.getCurrentToken() != JsonToken.FIELD_NAME) {
            tokLast = par.nextToken();
            locLast = par.getCurrentLocation();
          } else {
            tokLast = tokNew;
            locLast = locNew;
          }
        }
      }

      if (!endObject(par)) {
        // Can't rely on this exit condition inside the for loop because no readers may filter.
        return;
      }

      if (!extRead) {
        // No field was consumed by any reader, so we need to skip the field to make progress.
        if (logger.isDebugEnabled()) {
          logger.debug("Extension field not consumed by any reader, skipping: {} @{}:{}",
              par.getCurrentName(), locLast.getLineNr(), locLast.getCharOffset());
        }
        par.nextToken();
        par.skipChildren();
        tokLast = par.nextToken();
        locLast = par.getCurrentLocation();
      }
      // Else loop, try all readers again
    }
  }
Read any extensions that may exist in a message.

@param msg Builder of a message that may contain extensions
@param par The JSON parser, positioned at the "ext" field
@param <EB> Type of message builder being constructed
@throws IOException any parsing error