org.mashti.jetson.util.JsonParserUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.mashti.jetson.util.JsonParserUtil.java

Source

/**
 * This file is part of jetson.
 *
 * jetson is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * jetson is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with jetson.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.mashti.jetson.util;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.core.type.TypeReference;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.Arrays;

/**
 * A utility class for parsing a JSON stream using {@link JsonParser}.
 *
 * @author Masih Hajiarabderkani (mh638@st-andrews.ac.uk)
 */
public final class JsonParserUtil {

    private JsonParserUtil() {

    }

    /**
     * Consumes a field name from a JSON stream and checks that the filed name matches one of the given {@code filed_names}.
     * Throws {@link JsonParseException} if the consumed field name does not match any of the given {@code field_names}.
     *
     * @param parser the parser to read from
     * @param field_names the field names to match
     * @return the matched field name
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static String expectFieldNames(final JsonParser parser, final String... field_names) throws IOException {

        final String next_field_name = nextFieldName(parser);
        for (final String field_name : field_names) {
            if (next_field_name.equals(field_name)) {
                return next_field_name;
            }
        }
        throw new JsonParseException("expected one of field names " + Arrays.toString(field_names),
                parser.getCurrentLocation());
    }

    /**
     * Consumes a field name from a JSON stream and checks that the filed name matches the given {@code filed_name}.
     * Throws {@link JsonParseException} if the consumed field name does not match the given {@code field_name}.
     *
     * @param parser the parser to read from
     * @param field_name the field name to expect
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static void expectFieldName(final JsonParser parser, final String field_name) throws IOException {

        if (!nextFieldName(parser).equals(field_name)) {
            throw new JsonParseException("expected the field name " + field_name, parser.getCurrentLocation());
        }
    }

    /**
     * Consumes the next token from a JSON stream and checks that the token is a {@link JsonToken#FIELD_NAME}.
     * Throws {@link JsonParseException} if the token is not a {@link JsonToken#FIELD_NAME}.
     *
     * @param parser the parser to read from
     * @return the field name
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private static String nextFieldName(final JsonParser parser) throws IOException {

        if (parser.nextToken() == JsonToken.FIELD_NAME) {
            return parser.getCurrentName();
        }
        throw new JsonParseException("expected some field name", parser.getCurrentLocation());
    }

    /**
     * Reads a field and its value as the given {@code expected_type}.
     *
     * @param <T> the generic type
     * @param parser the parser
     * @param expected_filed_name the expected filed name
     * @param expected_type the expected type of the field value
     * @return the value
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static <T> T readFieldValueAs(final JsonParser parser, final String expected_filed_name,
            final Class<T> expected_type) throws IOException {

        expectFieldName(parser, expected_filed_name);
        return readValueAs(parser, expected_type);
    }

    /**
     * Reads the values of a JSON array as the proved types.
     *
     * @param parser the parser
     * @param expected_types the expected types of array values
     * @return the array values
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static Object[] readArrayValuesAs(final JsonParser parser, final Type[] expected_types)
            throws IOException {

        expectStartArray(parser);
        final int expected_values_length = expected_types.length;
        final Object[] params;
        if (expected_values_length != 0) {
            params = new Object[expected_values_length];
            for (int i = 0; i < expected_values_length; i++) {
                params[i] = readValueAs(parser, expected_types[i]);
            }
        } else {
            params = null;
        }
        expectEndArray(parser);
        return params;
    }

    /**
     * Expects start array.
     *
     * @param parser the parser
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private static void expectStartArray(final JsonParser parser) throws IOException {

        if (parser.nextToken() != JsonToken.START_ARRAY) {
            throw new JsonParseException("expected start array", parser.getCurrentLocation());
        }
    }

    /**
     * Consumes the next token from a JSON stream and checks that the token is a {@link JsonToken#START_ARRAY}.
     * Throws {@link JsonParseException} if the token is not a {@link JsonToken#START_ARRAY}.
     *
     * @param parser the parser to read from
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private static void expectEndArray(final JsonParser parser) throws IOException {

        if (parser.nextToken() != JsonToken.END_ARRAY) {
            throw new JsonParseException("expected end array", parser.getCurrentLocation());
        }
    }

    /**
     * Reads a field value as the provided type. This method supports parametrised types.
     *
     * @param parser the parser
     * @param expected_type the expected type of the value
     * @return the value
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static Object readValueAs(final JsonParser parser, final Type expected_type) throws IOException {

        final Object value;
        if (expected_type.equals(Void.TYPE)) {
            expectNullValue(parser);
            value = null;
        } else {
            parser.nextToken();
            value = parser.readValueAs(toTypeReference(expected_type));
        }
        return value;
    }

    /**
     * Consumes the next token from a JSON stream and checks that the token is a {@link JsonToken#VALUE_NULL}.
     * Throws {@link JsonParseException} if the token is not a {@link JsonToken#VALUE_NULL}.
     *
     * @param parser the parser to read from
     * @throws IOException Signals that an I/O exception has occurred.
     */
    private static void expectNullValue(final JsonParser parser) throws IOException {

        if (parser.nextToken() != JsonToken.VALUE_NULL) {
            throw new JsonParseException("expected null value", parser.getCurrentLocation());
        }
    }

    /**
     * Reads a field value as the provided type.
     *
     * @param <Value> the value type
     * @param parser the parser
     * @param expected_type the expected type of the value
     * @return the value
     * @throws IOException Signals that an I/O exception has occurred.
     */
    public static <Value> Value readValueAs(final JsonParser parser, final Class<Value> expected_type)
            throws IOException {

        final Value value;
        if (expected_type.equals(Void.TYPE)) {
            expectNullValue(parser);
            value = null;
        } else {
            parser.nextToken();
            value = parser.readValueAs(expected_type);
        }
        return value;
    }

    static RuntimeTypeReference toTypeReference(final Type type) {

        return new RuntimeTypeReference(type);
    }

    private static final class RuntimeTypeReference extends TypeReference<Object> {

        private final Type expected_type;

        private RuntimeTypeReference(final Type expected_type) {

            this.expected_type = expected_type;
        }

        @Override
        public Type getType() {

            return expected_type;
        }
    }
}