com.ryan.ryanreader.jsonwrap.JsonBufferedObject.java Source code

Java tutorial

Introduction

Here is the source code for com.ryan.ryanreader.jsonwrap.JsonBufferedObject.java

Source

/*******************************************************************************
 * This file is part of RedReader.
 *
 * RedReader 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.
 *
 * RedReader 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 RedReader.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/

package com.ryan.ryanreader.jsonwrap;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * A JSON object, which may be partially or fully received.
 */
public final class JsonBufferedObject extends JsonBuffered implements Iterable<Map.Entry<String, JsonValue>> {

    private final HashMap<String, JsonValue> properties = new HashMap<String, JsonValue>();

    @Override
    protected void buildBuffered(final JsonParser jp) throws IOException {

        JsonToken jt;

        while ((jt = jp.nextToken()) != JsonToken.END_OBJECT) {

            if (jt != JsonToken.FIELD_NAME)
                throw new JsonParseException("Expecting field name, got " + jt.name(), jp.getCurrentLocation());

            final String fieldName = jp.getCurrentName();
            final JsonValue value = new JsonValue(jp);

            synchronized (this) {
                properties.put(fieldName, value);
                notifyAll();
            }

            value.buildInThisThread();
        }
    }

    /**
     * This method will block until either: the specified field is received, the
     * object fails to parse, or the object is fully received and there is no
     * such field.
     * 
     * @param name
     *         The name of the field
     * @return The value contained in the specified field
     * @throws InterruptedException
     * @throws java.io.IOException
     */
    public JsonValue get(final String name) throws InterruptedException, IOException {

        synchronized (this) {

            while (getStatus() == Status.LOADING && !properties.containsKey(name)) {
                wait();
            }

            if (getStatus() != Status.FAILED || properties.containsKey(name)) {
                return properties.get(name);
            }

            if (getStatus() == Status.FAILED) {
                throwFailReasonException();
            }

            return null;
        }
    }

    /**
     * This method will block until either: the specified field is received, the
     * object fails to parse, or the object is fully received and there is no
     * such field.
     * 
     * @param name
     *         The name of the field
     * @return The value contained in the specified field
     * @throws InterruptedException
     * @throws java.io.IOException
     */
    public String getString(final String name) throws InterruptedException, IOException {
        return get(name).asString();
    }

    /**
     * This method will block until either: the specified field is received, the
     * object fails to parse, or the object is fully received and there is no
     * such field.
     * 
     * @param name
     *         The name of the field
     * @return The value contained in the specified field
     * @throws InterruptedException
     * @throws java.io.IOException
     */
    public Long getLong(final String name) throws InterruptedException, IOException {
        return get(name).asLong();
    }

    /**
     * This method will block until either: the specified field is received, the
     * object fails to parse, or the object is fully received and there is no
     * such field.
     * 
     * @param name
     *         The name of the field
     * @return The value contained in the specified field
     * @throws InterruptedException
     * @throws java.io.IOException
     */
    public Double getDouble(final String name) throws InterruptedException, IOException {
        return get(name).asDouble();
    }

    /**
     * This method will block until either: the specified field is received, the
     * object fails to parse, or the object is fully received and there is no
     * such field.
     * 
     * @param name
     *         The name of the field
     * @return The value contained in the specified field
     * @throws InterruptedException
     * @throws java.io.IOException
     */
    public Boolean getBoolean(final String name) throws InterruptedException, IOException {
        return get(name).asBoolean();
    }

    /**
     * This method will block until either: the specified field is received, the
     * object fails to parse, or the object is fully received and there is no
     * such field.
     * 
     * @param name
     *         The name of the field
     * @return The value contained in the specified field
     * @throws InterruptedException
     * @throws java.io.IOException
     */
    public JsonBufferedObject getObject(final String name) throws InterruptedException, IOException {
        return get(name).asObject();
    }

    public <E> E getObject(final String name, final Class<E> clazz) throws InterruptedException, IOException,
            InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        return get(name).asObject(clazz);
    }

    /**
     * This method will block until either: the specified field is received, the
     * object fails to parse, or the object is fully received and there is no
     * such field.
     * 
     * @param name
     *         The name of the field
     * @return The value contained in the specified field
     * @throws InterruptedException
     * @throws java.io.IOException
     */
    public JsonBufferedArray getArray(final String name) throws InterruptedException, IOException {
        return get(name).asArray();
    }

    @Override
    protected void prettyPrint(final int indent, final StringBuilder sb) throws InterruptedException, IOException {

        if (join() != Status.LOADED) {
            throwFailReasonException();
        }

        sb.append('{');

        final Set<String> propertyKeySet = properties.keySet();
        final String[] fieldNames = propertyKeySet.toArray(new String[propertyKeySet.size()]);

        for (int prop = 0; prop < fieldNames.length; prop++) {
            if (prop != 0)
                sb.append(',');
            sb.append('\n');
            for (int i = 0; i < indent + 1; i++)
                sb.append("   ");
            sb.append("\"").append(fieldNames[prop].replace("\\", "\\\\").replace("\"", "\\\"")).append("\": ");
            properties.get(fieldNames[prop]).prettyPrint(indent + 1, sb);
        }

        sb.append('\n');
        for (int i = 0; i < indent; i++)
            sb.append("   ");
        sb.append('}');
    }

    public <E> E asObject(final Class<E> clazz) throws InstantiationException, IllegalAccessException,
            InterruptedException, IOException, NoSuchMethodException, InvocationTargetException {
        final E obj = clazz.getConstructor().newInstance();
        populateObject(obj);
        return obj;
    }

    public void populateObject(final Object o) throws InterruptedException, IOException, IllegalArgumentException,
            InstantiationException, NoSuchMethodException, InvocationTargetException {

        if (join() != Status.LOADED) {
            throwFailReasonException();
        }

        final Field[] objectFields = o.getClass().getFields();

        try {

            for (final Field objectField : objectFields) {

                if ((objectField.getModifiers() & Modifier.TRANSIENT) != 0) {
                    continue;
                }

                final JsonValue val;

                if (properties.containsKey(objectField.getName())) {
                    val = properties.get(objectField.getName());

                } else if (objectField.getName().startsWith("_json_")) {
                    val = properties.get(objectField.getName().substring("_json_".length()));
                } else {
                    val = null;
                }

                if (val == null) {
                    continue;
                }

                objectField.setAccessible(true);

                final Class<?> fieldType = objectField.getType();

                if (fieldType == Long.class || fieldType == Long.TYPE) {
                    objectField.set(o, val.asLong());

                } else if (fieldType == Double.class || fieldType == Double.TYPE) {
                    objectField.set(o, val.asDouble());

                } else if (fieldType == Integer.class || fieldType == Integer.TYPE) {
                    objectField.set(o, val.isNull() ? null : val.asLong().intValue());

                } else if (fieldType == Float.class || fieldType == Float.TYPE) {
                    objectField.set(o, val.isNull() ? null : val.asDouble().floatValue());

                } else if (fieldType == Boolean.class || fieldType == Boolean.TYPE) {
                    objectField.set(o, val.asBoolean());

                } else if (fieldType == String.class) {
                    objectField.set(o, val.asString());

                } else if (fieldType == JsonBufferedArray.class) {
                    objectField.set(o, val.asArray());

                } else if (fieldType == JsonBufferedObject.class) {
                    objectField.set(o, val.asObject());

                } else if (fieldType == JsonValue.class) {
                    objectField.set(o, val);

                } else if (fieldType == Object.class) {

                    final Object result;

                    switch (val.getType()) {
                    case BOOLEAN:
                        result = val.asBoolean();
                        break;
                    case INTEGER:
                        result = val.asLong();
                        break;
                    case STRING:
                        result = val.asString();
                        break;
                    case FLOAT:
                        result = val.asDouble();
                        break;
                    default:
                        result = val;
                    }

                    objectField.set(o, result);

                } else {
                    objectField.set(o, val.asObject(fieldType));
                }
            }

        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public Iterator<Map.Entry<String, JsonValue>> iterator() {
        try {
            join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return properties.entrySet().iterator();
    }
}