Example usage for com.fasterxml.jackson.core JsonToken START_ARRAY

List of usage examples for com.fasterxml.jackson.core JsonToken START_ARRAY

Introduction

In this page you can find the example usage for com.fasterxml.jackson.core JsonToken START_ARRAY.

Prototype

JsonToken START_ARRAY

To view the source code for com.fasterxml.jackson.core JsonToken START_ARRAY.

Click Source Link

Document

START_ARRAY is returned when encountering '[' which signals starting of an Array value

Usage

From source file:com.bazaarvoice.jackson.rison.RisonParser.java

/**
 * @return Next token from the stream, if any found, or null
 *   to indicate end-of-input//from  www . j a  v a 2 s .  co  m
 */
@Override
public JsonToken nextToken() throws IOException, JsonParseException {
    _numTypesValid = NR_UNKNOWN;

    if (_currToken == null && _parsingContext.inRoot()) {
        if (isRisonEnabled(Feature.A_RISON)) {
            _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
            return (_currToken = JsonToken.START_ARRAY);
        } else if (isRisonEnabled(Feature.O_RISON)) {
            _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
            return (_currToken = JsonToken.START_OBJECT);
        }
    }

    /* First: field names are special -- we will always tokenize
     * (part of) value along with field name to simplify
     * state handling. If so, can and need to use secondary token:
     */
    if (_currToken == JsonToken.FIELD_NAME) {
        return _nextAfterName();
    }
    if (_tokenIncomplete) {
        _skipString(); // only strings can be partial
    }
    int i = _nextChOrEnd();
    if (i < 0) { // end-of-input
        /* 19-Feb-2009, tatu: Should actually close/release things
         *    like input source, symbol table and recyclable buffers now.
         */
        close();
        if (_parsingContext.getParent().inRoot()) {
            if (isRisonEnabled(Feature.A_RISON) && _parsingContext.inArray()) {
                _parsingContext = _parsingContext.getParent();
                return (_currToken = JsonToken.END_ARRAY);
            }
            if (isRisonEnabled(Feature.O_RISON) && _parsingContext.inObject()) {
                _parsingContext = _parsingContext.getParent();
                return (_currToken = JsonToken.END_OBJECT);
            }
        }
        _handleEOF();
        return (_currToken = null);
    }

    /* First, need to ensure we know the starting location of token
     * after skipping leading white space
     */
    _tokenInputTotal = _currInputProcessed + _inputPtr - 1;
    _tokenInputRow = _currInputRow;
    _tokenInputCol = _inputPtr - _currInputRowStart - 1;

    // finally: clear any data retained so far
    _binaryValue = null;

    // Closing scope?
    if (i == ')') {
        if (_parsingContext.inArray()) {
            _parsingContext = _parsingContext.getParent();
            return (_currToken = JsonToken.END_ARRAY);
        }
        if (_parsingContext.inObject()) {
            _parsingContext = _parsingContext.getParent();
            return (_currToken = JsonToken.END_OBJECT);
        }
        _reportMismatchedEndMarker(i, ')');
    }

    // Nope: do we then expect a comma?
    if (_parsingContext.expectComma()) {
        if (i != INT_COMMA) {
            _reportUnexpectedChar(i,
                    "was expecting comma to separate " + _parsingContext.getTypeDesc() + " entries");
        }
        i = _nextCh();
    }

    /* And should we now have a name? Always true for
     * Object contexts, since the intermediate 'expect-value'
     * state is never retained.
     */
    boolean inObject = _parsingContext.inObject();
    if (inObject) {
        // First, field name itself:
        String name;
        if (i != INT_APOSTROPHE) {
            name = _parseUnquotedFieldName(i);
        } else {
            name = _parseFieldName(i);
        }
        _parsingContext.setCurrentName(name);
        _currToken = JsonToken.FIELD_NAME;
        i = _nextCh();
        if (i != INT_COLON) {
            _reportUnexpectedChar(i, "was expecting a colon to separate field name and value");
        }
        i = _nextCh();
    }

    // Ok: we must have a value... what is it?

    JsonToken t;

    switch (i) {
    case INT_APOSTROPHE:
        _tokenIncomplete = true;
        t = JsonToken.VALUE_STRING;
        break;
    case '(':
        if (!inObject) {
            _parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
        }
        t = JsonToken.START_OBJECT;
        break;
    case ')':
        // Error: ')' is not valid at this point; valid closers have
        // been handled earlier
        _reportUnexpectedChar(i, "expected a value");

    case INT_MINUS:
        /* Should we have separate handling for plus? Although
        * it is not allowed per se, it may be erroneously used,
        * and could be indicate by a more specific error message.
        */
    case INT_0:
    case INT_1:
    case INT_2:
    case INT_3:
    case INT_4:
    case INT_5:
    case INT_6:
    case INT_7:
    case INT_8:
    case INT_9:
        t = parseNumberText(i);
        break;

    case '!':
        i = _nextCh();
        switch (i) {
        case '(':
            if (!inObject) {
                _parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
            }
            t = JsonToken.START_ARRAY;
            break;
        case INT_t:
            t = JsonToken.VALUE_TRUE;
            break;
        case INT_f:
            t = JsonToken.VALUE_FALSE;
            break;
        case INT_n:
            t = JsonToken.VALUE_NULL;
            break;
        default:
            t = _handleUnexpectedValue(i);
            break;
        }
        break;
    default:
        if (IdentifierUtils.isIdStartLenient(i)) {
            t = JsonToken.VALUE_STRING;
            _inputPtr--; // push back the first char
            _parseUnquotedString();
        } else {
            t = _handleUnexpectedValue(i);
        }
        break;
    }

    if (inObject) {
        _nextToken = t;
        return _currToken;
    }
    _currToken = t;
    return t;
}

From source file:com.netflix.hollow.jsonadapter.HollowJsonAdapter.java

private int addSubArray(JsonParser parser, String arrayType, HollowWriteRecord arrayRec) throws IOException {
    JsonToken token = parser.nextToken();
    arrayRec.reset();//from  ww w .  j  a v  a 2 s  . co  m

    HollowCollectionSchema schema = (HollowCollectionSchema) hollowSchemas.get(arrayType);
    ObjectFieldMapping valueRec = null;
    ObjectMappedFieldPath fieldMapping = null;

    while (token != JsonToken.END_ARRAY) {

        int elementOrdinal;

        if (token == JsonToken.START_OBJECT || token == JsonToken.START_ARRAY) {
            elementOrdinal = parseSubType(parser, token, schema.getElementType());
        } else {
            if (valueRec == null) {
                valueRec = getObjectFieldMapping(schema.getElementType());
                fieldMapping = valueRec.getSingleFieldMapping();
            }

            addObjectField(parser, token, fieldMapping);
            elementOrdinal = valueRec.build(-1);
        }

        if (arrayRec instanceof HollowListWriteRecord) {
            ((HollowListWriteRecord) arrayRec).addElement(elementOrdinal);
        } else {
            ((HollowSetWriteRecord) arrayRec).addElement(elementOrdinal);
        }

        token = parser.nextToken();
    }

    return stateEngine.add(arrayType, arrayRec);
}

From source file:de.undercouch.bson4jackson.BsonParser.java

/**
 * Can be called when a new embedded document is found. Reads the
 * document's header and creates a new context on the stack.
 * @param array true if the document is an embedded array
 * @return the json token read// w ww.j  a  va2  s . c  o  m
 * @throws IOException if an I/O error occurs
 */
protected JsonToken handleNewDocument(boolean array) throws IOException {
    if (_in == null) {
        //this means Feature.HONOR_DOCUMENT_LENGTH is enabled, and we
        //haven't yet started reading. Read the first int to find out the
        //length of the document.
        byte[] buf = new byte[Integer.SIZE / Byte.SIZE];
        int len = 0;
        while (len < buf.length) {
            int l = _rawInputStream.read(buf, len, buf.length - len);
            if (l == -1) {
                throw new IOException("Not enough bytes for length of document");
            }
            len += l;
        }

        //wrap the input stream by a bounded stream, subtract buf.length from the
        //length because the size itself is included in the length
        int documentLength = ByteBuffer.wrap(buf).order(ByteOrder.LITTLE_ENDIAN).getInt();
        InputStream in = new BoundedInputStream(_rawInputStream, documentLength - buf.length);

        //buffer if the raw input stream is not already buffered
        if (!(_rawInputStream instanceof BufferedInputStream)) {
            in = new StaticBufferedInputStream(in);
        }
        _counter = new CountingInputStream(in);
        _in = new LittleEndianInputStream(_counter);
    } else {
        //read document header (skip size, we're not interested)
        _in.readInt();
    }

    _currentContext = new Context(_currentContext, array);
    return (array ? JsonToken.START_ARRAY : JsonToken.START_OBJECT);
}

From source file:com.amazonaws.services.cloudtrail.processinglibrary.serializer.AbstractEventSerializer.java

/**
 * Parse a list of Resource/*from  w  w  w.j a va  2s .c o  m*/
 *
 * @param eventData the resources belong to
 * @throws IOException
 */
private void parseResources(CloudTrailEventData eventData) throws IOException {
    JsonToken nextToken = this.jsonParser.nextToken();
    if (nextToken == JsonToken.VALUE_NULL) {
        eventData.add(CloudTrailEventField.resources.name(), null);
        return;
    }

    if (nextToken != JsonToken.START_ARRAY) {
        throw new JsonParseException("Not a list of resources object", this.jsonParser.getCurrentLocation());
    }

    List<Resource> resources = new ArrayList<Resource>();

    while (this.jsonParser.nextToken() != JsonToken.END_ARRAY) {
        resources.add(this.parseResource());
    }

    eventData.add(CloudTrailEventField.resources.name(), resources);
}

From source file:com.netflix.hollow.jsonadapter.HollowJsonAdapter.java

private int addStructuredMap(JsonParser parser, String mapTypeName, HollowMapWriteRecord mapRec)
        throws IOException {
    JsonToken token = parser.nextToken();
    mapRec.reset();//from w  w  w .ja va2s .  c  om

    HollowMapSchema schema = (HollowMapSchema) hollowSchemas.get(mapTypeName);

    while (token != JsonToken.END_ARRAY) {
        if (token == JsonToken.START_OBJECT) {
            int keyOrdinal = -1, valueOrdinal = -1;
            while (token != JsonToken.END_OBJECT) {

                if (token == JsonToken.START_OBJECT || token == JsonToken.START_ARRAY) {
                    if ("key".equals(parser.getCurrentName()))
                        keyOrdinal = parseSubType(parser, token, schema.getKeyType());
                    else if ("value".equals(parser.getCurrentName()))
                        valueOrdinal = parseSubType(parser, token, schema.getValueType());
                }

                token = parser.nextToken();
            }

            mapRec.addEntry(keyOrdinal, valueOrdinal);
        }

        token = parser.nextToken();
    }

    return stateEngine.add(schema.getName(), mapRec);
}

From source file:org.apache.lucene.server.handlers.AddDocumentHandler.java

/** Parses the current json token into the corresponding
 *  java object. *//*from  w  ww.  j  av  a 2 s . c  o m*/
private static Object getNativeValue(FieldDef fd, JsonToken token, JsonParser p) throws IOException {
    Object o;
    if (token == JsonToken.VALUE_STRING) {
        o = p.getText();
    } else if (token == JsonToken.VALUE_NUMBER_INT) {
        o = Long.valueOf(p.getLongValue());
    } else if (token == JsonToken.VALUE_NUMBER_FLOAT) {
        o = Double.valueOf(p.getDoubleValue());
    } else if (token == JsonToken.VALUE_TRUE) {
        o = Boolean.TRUE;
    } else if (token == JsonToken.VALUE_FALSE) {
        o = Boolean.FALSE;
    } else if (fd.faceted.equals("hierarchy") && token == JsonToken.START_ARRAY) {
        if (fd.multiValued == false) {
            List<String> values = new ArrayList<>();
            while (true) {
                token = p.nextToken();
                if (token == JsonToken.END_ARRAY) {
                    break;
                } else if (token != JsonToken.VALUE_STRING) {
                    if (token == JsonToken.START_ARRAY) {
                        fail(fd.name, "expected array of strings, but saw array inside array");
                    } else {
                        fail(fd.name, "expected array of strings, but saw " + token + " inside array");
                    }
                }
                values.add(p.getText());
            }
            o = values;
        } else {
            List<List<String>> values = new ArrayList<>();
            while (true) {
                token = p.nextToken();
                if (token == JsonToken.END_ARRAY) {
                    break;
                } else if (token == JsonToken.START_ARRAY) {
                    List<String> sub = new ArrayList<>();
                    values.add(sub);
                    while (true) {
                        token = p.nextToken();
                        if (token == JsonToken.VALUE_STRING) {
                            sub.add(p.getText());
                        } else if (token == JsonToken.END_ARRAY) {
                            break;
                        } else {
                            fail(fd.name, "expected array of strings or array of array of strings, but saw "
                                    + token + " inside inner array");
                        }
                    }
                } else if (token == JsonToken.VALUE_STRING) {
                    List<String> sub = new ArrayList<>();
                    values.add(sub);
                    sub.add(p.getText());
                } else if (token == JsonToken.START_ARRAY) {
                    fail(fd.name, "expected array of strings, but saw array inside array");
                } else {
                    fail(fd.name, "expected array of strings, but saw " + token + " inside array");
                }
            }
            o = values;
        }
    } else if (fd.valueType == FieldDef.FieldValueType.LAT_LON) {
        if (token != JsonToken.START_ARRAY) {
            fail(fd.name, "latlon field must be [lat, lon] value; got " + token);
        }
        double[] latLon = new double[2];
        token = p.nextToken();
        if (token != JsonToken.VALUE_NUMBER_FLOAT) {
            fail(fd.name, "latlon field must be [lat, lon] value; got " + token);
        }
        latLon[0] = p.getDoubleValue();
        token = p.nextToken();
        if (token != JsonToken.VALUE_NUMBER_FLOAT) {
            fail(fd.name, "latlon field must be [lat, lon] value; got " + token);
        }
        latLon[1] = p.getDoubleValue();
        token = p.nextToken();
        if (token != JsonToken.END_ARRAY) {
            fail(fd.name, "latlon field must be [lat, lon] value; got " + token);
        }
        o = latLon;
    } else {
        String message;
        if (token == JsonToken.VALUE_NULL) {
            message = "null field value not supported; just omit this field from the document instead";
        } else {
            message = "value in inner object field value should be string, int/long, float/double or boolean; got "
                    + token;
        }

        fail(fd.name, message);

        // Dead code but compiler disagrees:
        o = null;
    }
    return o;
}

From source file:com.couchbase.lite.replicator.ChangeTracker.java

protected void runLoop() {
    paused = false;//from   ww w .j  a va  2s. com

    if (client == null) {
        // This is a race condition that can be reproduced by calling cbpuller.start() and cbpuller.stop()
        // directly afterwards.  What happens is that by the time the Changetracker thread fires up,
        // the cbpuller has already set this.client to null.  See issue #109
        Log.w(Log.TAG_CHANGE_TRACKER, "%s: ChangeTracker run() loop aborting because client == null", this);
        return;
    }

    if (mode == ChangeTrackerMode.Continuous) {
        // there is a failing unit test for this, and from looking at the code the Replication
        // object will never use Continuous mode anyway.  Explicitly prevent its use until
        // it is demonstrated to actually work.
        throw new RuntimeException("ChangeTracker does not correctly support continuous mode");
    }

    OkHttpClient httpClient = client.getOkHttpClient();

    backoff = new ChangeTrackerBackoff();

    while (running) {
        startTime = System.currentTimeMillis();

        Request.Builder builder = new Request.Builder();
        URL url = getChangesFeedURL();
        builder.url(url);
        if (usePOST) {
            builder.header("Content-Type", "application/json").addHeader("User-Agent", Manager.getUserAgent())
                    .addHeader("Accept-Encoding", "gzip").post(RequestBody.create(JSON, changesFeedPOSTBody()));
        }
        addRequestHeaders(builder);

        // Perform BASIC Authentication if needed
        builder = RequestUtils.preemptivelySetAuthCredentials(builder, url, authenticator);
        request = builder.build();

        try {
            String maskedRemoteWithoutCredentials = getChangesFeedURL().toString();
            maskedRemoteWithoutCredentials = maskedRemoteWithoutCredentials.replaceAll("://.*:.*@",
                    "://---:---@");
            Log.v(Log.TAG_CHANGE_TRACKER, "%s: Making request to %s", this, maskedRemoteWithoutCredentials);
            call = httpClient.newCall(request);
            Response response = call.execute();
            try {
                // In case response status is Error, ChangeTracker stops here
                if (isResponseFailed(response)) {
                    RequestUtils.closeResponseBody(response);
                    if (retryIfFailedPost(response))
                        continue;
                    break;
                }

                // Parse response body
                ResponseBody responseBody = response.body();

                Log.v(Log.TAG_CHANGE_TRACKER, "%s: got response. status: %s mode: %s", this, response.message(),
                        mode);
                if (responseBody != null) {
                    try {
                        Log.v(Log.TAG_CHANGE_TRACKER, "%s: /entity.getContent().  mode: %s", this, mode);
                        //inputStream = entity.getContent();
                        inputStream = responseBody.byteStream();
                        // decompress if contentEncoding is gzip
                        if (Utils.isGzip(response))
                            inputStream = new GZIPInputStream(inputStream);

                        if (mode == ChangeTrackerMode.LongPoll) { // continuous replications
                            // NOTE: 1. check content length, ObjectMapper().readValue() throws Exception if size is 0.
                            // NOTE: 2. HttpEntity.getContentLength() returns the number of bytes of the content, or a negative number if unknown.
                            // NOTE: 3. If Http Status is error, not parse response body
                            boolean responseOK = false; // default value
                            if (responseBody.contentLength() != 0 && response.code() < 300) {
                                try {
                                    Log.v(Log.TAG_CHANGE_TRACKER, "%s: readValue", this);
                                    Map<String, Object> fullBody = Manager.getObjectMapper()
                                            .readValue(inputStream, Map.class);
                                    Log.v(Log.TAG_CHANGE_TRACKER, "%s: /readValue.  fullBody: %s", this,
                                            fullBody);
                                    responseOK = receivedPollResponse(fullBody);
                                } catch (JsonParseException jpe) {
                                    Log.w(Log.TAG_CHANGE_TRACKER, "%s: json parsing error; %s", this,
                                            jpe.toString());
                                } catch (JsonMappingException jme) {
                                    Log.w(Log.TAG_CHANGE_TRACKER, "%s: json mapping error; %s", this,
                                            jme.toString());
                                }
                            }
                            Log.v(Log.TAG_CHANGE_TRACKER, "%s: responseOK: %s", this, responseOK);

                            if (responseOK) {
                                // TODO: this logic is questionable, there's lots
                                // TODO: of differences in the iOS changetracker code,
                                if (!caughtUp) {
                                    caughtUp = true;
                                    client.changeTrackerCaughtUp();
                                }
                                Log.v(Log.TAG_CHANGE_TRACKER, "%s: Starting new longpoll", this);
                                backoff.resetBackoff();
                                continue;
                            } else {
                                long elapsed = (System.currentTimeMillis() - startTime) / 1000;
                                Log.w(Log.TAG_CHANGE_TRACKER,
                                        "%s: Longpoll connection closed (by proxy?) after %d sec", this,
                                        elapsed);
                                if (elapsed >= 30) {
                                    // Looks like the connection got closed by a proxy (like AWS' load balancer) while the
                                    // server was waiting for a change to send, due to lack of activity.
                                    // Lower the heartbeat time to work around this, and reconnect:
                                    this.heartBeatSeconds = Math.min(this.heartBeatSeconds,
                                            (int) (elapsed * 0.75));
                                    Log.v(Log.TAG_CHANGE_TRACKER, "%s: Starting new longpoll", this);
                                    backoff.resetBackoff();
                                    continue;
                                } else {
                                    Log.d(Log.TAG_CHANGE_TRACKER, "%s: Change tracker calling stop (LongPoll)",
                                            this);
                                    client.changeTrackerFinished(this);
                                    break;
                                }
                            }
                        } else { // one-shot replications
                            Log.v(Log.TAG_CHANGE_TRACKER, "%s: readValue (oneshot)", this);
                            JsonFactory factory = new JsonFactory();
                            JsonParser jp = factory.createParser(inputStream);
                            JsonToken token;
                            // nextToken() is null => no more token
                            while (((token = jp.nextToken()) != JsonToken.START_ARRAY) && (token != null)) {
                                // ignore these tokens
                            }
                            while (jp.nextToken() == JsonToken.START_OBJECT) {
                                Map<String, Object> change = (Map) Manager.getObjectMapper().readValue(jp,
                                        Map.class);
                                if (!receivedChange(change)) {
                                    Log.w(Log.TAG_CHANGE_TRACKER,
                                            "Received unparseable change line from server: %s", change);
                                }
                                // if not running state anymore, exit from loop.
                                if (!running)
                                    break;
                            }
                            if (jp != null)
                                jp.close();

                            Log.v(Log.TAG_CHANGE_TRACKER, "%s: /readValue (oneshot)", this);
                            client.changeTrackerCaughtUp();
                            if (isContinuous()) { // if enclosing replication is continuous
                                mode = ChangeTrackerMode.LongPoll;
                            } else {
                                Log.d(Log.TAG_CHANGE_TRACKER, "%s: Change tracker calling stop (OneShot)",
                                        this);
                                client.changeTrackerFinished(this);
                                break;
                            }
                        }
                        backoff.resetBackoff();
                    } finally {
                        try {
                            if (inputStream != null) {
                                inputStream.close();
                                inputStream = null;
                            }
                        } catch (IOException e) {
                        }
                    }
                }
            } finally {
                RequestUtils.closeResponseBody(response);
            }
        } catch (Exception e) {
            if (!running && e instanceof IOException) {
                // in this case, just silently absorb the exception because it
                // frequently happens when we're shutting down and have to
                // close the socket underneath our read.
            } else {
                Log.w(Log.TAG_CHANGE_TRACKER, this + ": Exception in change tracker", e);
                this.error = e;
            }
            backoff.sleepAppropriateAmountOfTime();
        }
    }
    Log.v(Log.TAG_CHANGE_TRACKER, "%s: Change tracker run loop exiting", this);
}

From source file:com.zenesis.qx.remote.RequestHandler.java

private Object[] readParameters(JsonParser jp, Class[] types) throws IOException {
    if (types == null) {
        // Check for parameters
        if (jp.getCurrentToken() == JsonToken.FIELD_NAME && jp.getCurrentName().equals("parameters")
                && jp.nextToken() == JsonToken.START_ARRAY) {
            while (jp.nextToken() != JsonToken.END_ARRAY)
                ;/*from  w  w w  . j a v  a 2s  . c om*/
        }
        return null;
    }
    Object[] values = new Object[types.length];
    Object[] params = null;

    // Check for parameters
    if (jp.getCurrentToken() == JsonToken.FIELD_NAME && jp.getCurrentName().equals("parameters")
            && jp.nextToken() == JsonToken.START_ARRAY) {

        params = readArray(jp, types);
    }

    for (int i = 0; i < values.length; i++)
        if (i < params.length)
            values[i] = params[i];
        else
            values[i] = null;

    return values;
}

From source file:com.amazonaws.services.cloudtrail.processinglibrary.serializer.AbstractEventSerializer.java

/**
 * Parse the event with key as default value.
 *
 * If the value is JSON null, then we will return null.
 * If the value is JSON object (of starting with START_ARRAY or START_OBject) , then we will convert the object to String.
 * If the value is JSON scalar value (non-structured object), then we will return simply return it as String.
 *
 * @param key/*from   w ww.ja v a  2  s  . c  o m*/
 * @throws IOException
 */
private String parseDefaultValue(String key) throws IOException {
    this.jsonParser.nextToken();
    String value = null;
    JsonToken currentToken = this.jsonParser.getCurrentToken();
    if (currentToken != JsonToken.VALUE_NULL) {
        if (currentToken == JsonToken.START_ARRAY || currentToken == JsonToken.START_OBJECT) {
            JsonNode node = this.jsonParser.readValueAsTree();
            value = node.toString();
        } else {
            value = this.jsonParser.getValueAsString();
        }
    }
    return value;
}

From source file:io.protostuff.JsonIOUtil.java

/**
 * Parses the {@code messages} from the parser using the given {@code schema}.
 *//*from   www .j a  va2 s .c  o m*/
public static <T> List<T> parseListFrom(JsonParser parser, Schema<T> schema, boolean numeric)
        throws IOException {
    if (parser.nextToken() != JsonToken.START_ARRAY) {
        throw new JsonInputException("Expected token: [ but was " + parser.getCurrentToken() + " on message: "
                + schema.messageFullName());
    }

    final JsonInput input = new JsonInput(parser, numeric);
    final List<T> list = new ArrayList<>();
    for (JsonToken t = parser.nextToken(); t != JsonToken.END_ARRAY; t = parser.nextToken()) {
        if (t != JsonToken.START_OBJECT) {
            throw new JsonInputException("Expected token: { but was " + parser.getCurrentToken()
                    + " on message " + schema.messageFullName());
        }

        final T message = schema.newMessage();
        schema.mergeFrom(input, message);

        if (parser.getCurrentToken() != JsonToken.END_OBJECT) {
            throw new JsonInputException("Expected token: } but was " + parser.getCurrentToken()
                    + " on message " + schema.messageFullName());
        }

        list.add(message);
        input.reset();
    }
    return list;
}