io.robusta.rra.representation.implementation.GsonRepresentation.java Source code

Java tutorial

Introduction

Here is the source code for io.robusta.rra.representation.implementation.GsonRepresentation.java

Source

/*
 * Copyright (c) 2014. by Robusta Code and individual contributors
 *  as indicated by the @authors tag. See the copyright.txt in the
 * distribution for a full listing of individual contributors.
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package io.robusta.rra.representation.implementation;

import io.robusta.rra.representation.JsonRepresentation;
import io.robusta.rra.representation.Representation;
import io.robusta.rra.representation.RepresentationException;
import io.robusta.rra.resource.Resource;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.stream.JsonReader;

/**
 * Created by Nicolas Zozol for Robusta Code
 * <p/>
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 * 
 * @author Nicolas Zozol
 *
 */
public class GsonRepresentation implements JsonRepresentation<JsonElement> {

    Gson gson = new Gson();
    JsonElement document;
    List<String> missingKeys = new ArrayList<String>(5);

    /**
     * In that case, is serialization if not null, it's always a JsonObject
     *
     * @param serialization
     */
    public GsonRepresentation(HashMap<String, Object> serialization) {
        this.document = gson.toJsonTree(serialization);
    }

    /**
     * contructor
     * 
     * @param object
     */
    public GsonRepresentation(Object object) {
        this.document = gson.toJsonTree(object);
    }

    /**
     * contructor
     * 
     * @param json
     */
    public GsonRepresentation(String json) {
        this.document = new JsonParser().parse(json);
    }

    /**
     * contructor
     * 
     * @param inputStream
     */
    public GsonRepresentation(InputStream inputStream) {
        this.document = new JsonParser().parse(new JsonReader(new InputStreamReader(inputStream)));
    }

    /**
     * contructor
     */
    public GsonRepresentation() {
        this.document = null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#getDocument()
     */
    @Override
    public JsonElement getDocument() {
        return this.document;
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#get(java.lang.Class)
     */
    @Override
    public <T> T get(Class<T> type) throws RepresentationException {
        return get(type, this.document);
    }

    // TODO : rename to map() ?
    /**
     * convert a jsonElement into Object
     * 
     * @param type
     * @param element
     * @return
     * @throws RepresentationException
     */
    protected <T> T get(Class<T> type, JsonElement element) throws RepresentationException {

        if (type == Long.class) {
            return (T) (Long) element.getAsLong();
        } else if (type == Integer.class) {
            return (T) (Integer) element.getAsInt();
        } else if (type == Short.class) {
            return (T) (Short) element.getAsShort();
        } else if (type == Byte.class) {
            return (T) (Byte) element.getAsByte();
        } else if (type == BigInteger.class) {
            return (T) (BigInteger) element.getAsBigInteger();
        } else if (type == Double.class) {
            return (T) (Double) element.getAsDouble();
        } else if (type == Float.class) {
            return (T) (Float) element.getAsFloat();
        } else if (type == BigDecimal.class) {
            return (T) (BigDecimal) element.getAsBigDecimal();
        } else if (type == Boolean.class) {
            return (T) (Boolean) element.getAsBoolean();
        } else if (type == String.class) {
            return (T) element.getAsString();
        } else {
            return (T) gson.fromJson(element, type);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#get(java.lang.String)
     */
    @Override
    public String get(String key) throws RepresentationException {
        return this.get(String.class, key);
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#get(java.lang.Class,
     * java.lang.String)
     */
    @Override
    public <T> T get(Class<T> type, String key) throws RepresentationException {

        JsonElement element = this.document.getAsJsonObject().get(key);
        return get(type, element);

    }

    /**
     * check if document has the specified keys
     * 
     * @param key
     * @return
     */
    protected boolean has(String key) {

        throwIfNotObject(this.document);

        JsonObject object = this.document.getAsJsonObject();
        return object.has(key);

    }

    /**
     * check if document is not null
     * 
     * @param key
     * @return
     */
    protected boolean hasNotEmpty(String key) {
        throwIfNotObject();
        JsonObject object = this.document.getAsJsonObject();
        JsonElement elt = object.get(key);
        if (elt == null || elt.isJsonNull() || (isString(elt) && elt.getAsString().isEmpty())) {
            // elt is null or empty string
            return false;
        } else {
            return true;
        }

    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * io.robusta.rra.representation.Representation#hasPossiblyEmpty(java.lang
     * .String[])
     */
    @Override
    public boolean hasPossiblyEmpty(String... keys) {
        boolean result = true;
        for (String key : keys) {
            if (!has(key)) {
                missingKeys.add(key);
                result = false;
            }
        }
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#has(java.lang.String[])
     */
    @Override
    public boolean has(String... keys) {
        boolean result = true;
        for (String key : keys) {
            if (!hasNotEmpty(key)) {
                missingKeys.add(key);
                result = false;
            }
        }
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#getMissingKeys()
     */
    @Override
    public List<String> getMissingKeys() {
        return missingKeys;
    }

    /**
     * if document is null, create a new document
     */
    protected void createObjectIfEmtpy() {
        if (this.document == null) {
            this.document = new JsonObject();
        }
    }

    /**
     * throw an exception if the jsonElement is null
     * 
     * @param elt
     * @throws RepresentationException
     */
    protected void throwIfNull(JsonElement elt) throws RepresentationException {
        if (elt == null) {
            throw new RepresentationException("The current element is null");
        }
    }

    /**
     * throw an exception if the jsonElement is not an object
     * 
     * @param elt
     * @throws RepresentationException
     */
    protected void throwIfNotObject(JsonElement elt) throws RepresentationException {
        if (!elt.isJsonObject()) {
            throw new RepresentationException(
                    "The current element is not a JSON object but a " + this.getTypeof() + " and thus has no key");
        }
    }

    /**
     * throw an exception if the document is not an object
     * 
     * @throws RepresentationException
     */
    protected void throwIfNotObject() throws RepresentationException {
        throwIfNull(this.document);
        throwIfNotObject(this.document);
    }

    /**
     * throw an exception if the jsonElement is not an array
     * 
     * @param elt
     * @throws RepresentationException
     */
    protected void throwIfNotArray(JsonElement elt) throws RepresentationException {
        if (!elt.isJsonArray()) {
            throw new RepresentationException("The current element is not a JSON array but a " + this.getTypeof()
                    + " and it can't add an object the correct way");
        }
    }

    /**
     * throw an exception if the document is not an array
     * @throws RepresentationException
     */
    protected void throwIfNotArray() throws RepresentationException {
        throwIfNull(this.document);
        throwIfNotArray(this.document);
    }

    /**
     * convert the document into a JsonArray and return it. 
     * throw an exception if the document is not an object
     * @return
     */
    protected JsonObject asObject() {
        throwIfNotObject();
        return this.document.getAsJsonObject();
    }

    /**
     * convert the document into a JsonArray and return it. 
     * throw an exception if the document is not an array
     * @return
     */
    protected JsonArray asArray() {
        throwIfNotArray();
        return this.document.getAsJsonArray();
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#set(java.lang.String,
     * java.lang.String)
     */
    @Override
    public Representation set(String key, String value) {
        createObjectIfEmtpy();
        asObject().add(key, new JsonPrimitive(value));
        return this;
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#set(java.lang.String,
     * java.lang.Object)
     */
    @Override
    public Representation set(String key, Object value) {
        createObjectIfEmtpy();
        asObject().add(key, gson.toJsonTree(value));
        return this;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * io.robusta.rra.representation.Representation#getValues(java.lang.String)
     */
    @Override
    public List<String> getValues(String key) throws RepresentationException {
        List<String> list = new ArrayList<String>();
        for (JsonElement elt : asObject().get(key).getAsJsonArray()) {
            list.add(elt.toString());
        }
        return list;
    }

    // TODO : Not tested. If it works here, that's great !!
    /*
     * (non-Javadoc)
     * 
     * @see
     * io.robusta.rra.representation.Representation#getValues(java.lang.Class,
     * java.lang.String)
     */
    @Override
    public <T> List<T> getValues(Class<T> type, String key) throws RepresentationException {
        List<T> list = new ArrayList<T>();
        for (JsonElement elt : asObject().get(key).getAsJsonArray()) {
            list.add(get(type, elt));
        }
        return list;
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#add(java.lang.String,
     * java.lang.Object)
     */
    @Override
    public Representation add(String key, Object value) {
        throwIfNotObject();
        throwIfNotArray(this.asObject().get(key));
        asObject().get(key).getAsJsonArray().add(gson.toJsonTree(value));
        return this;
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#add(java.lang.String,
     * io.robusta.rra.resource.Resource, boolean)
     */
    @Override
    public Representation add(String key, Resource resource, boolean eager) {
        throwIfNotObject();
        throwIfNotArray(this.asObject().get(key));
        // TODO : to use eager, we must look at ReflectiveTypeAdapterFactory
        // around line 82
        JsonElement element = gson.toJsonTree(resource);
        asObject().get(key).getAsJsonArray().add(element);
        return this;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * io.robusta.rra.representation.Representation#addAll(java.lang.String,
     * java.util.List)
     */
    @Override
    public Representation addAll(String key, List values) {
        throwIfNotObject();
        throwIfNotArray(this.asObject().get(key));
        JsonArray array = this.asObject().get(key).getAsJsonArray();
        for (Object value : values) {
            array.add(gson.toJsonTree(value));
        }

        return this;
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#merge(java.lang.String,
     * java.lang.String, io.robusta.rra.representation.Representation)
     */
    @Override
    public Representation merge(String keyForCurrent, String keyForNew, Representation representation) {
        if (!(representation instanceof GsonRepresentation)) {
            throw new IllegalArgumentException(
                    "Can't merge a GsonRepresentation with a " + representation.getClass().getSimpleName());
        }
        GsonRepresentation mergedRepresentation = new GsonRepresentation();
        mergedRepresentation.createObject();
        JsonObject object = mergedRepresentation.document.getAsJsonObject();
        object.add(keyForCurrent, this.document);
        object.add(keyForNew, ((GsonRepresentation) representation).document);
        return mergedRepresentation;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * io.robusta.rra.representation.Representation#remove(java.lang.String)
     */
    @Override
    public Representation remove(String key) throws RepresentationException {
        int i = 0;
        if (key.contains(".")) {
            String[] keys = key.split("\\.");
            if (keys.length == 0) {
                throw new IllegalArgumentException(
                        "Malformed key " + keys + " ; use something like user.school.id");
            }
            JsonElement current = asObject();
            for (i = 0; i < keys.length - 1; i++) {
                current = current.getAsJsonObject().get(keys[i]);
                if (current == null) {
                    throw new IllegalArgumentException(
                            "There is no valid object for key " + keys[i] + " in '" + key + "'");
                }
            }
            if (current.getAsJsonObject().get(keys[keys.length - 1]) == null) {
                throw new IllegalArgumentException(
                        "There is no valid object for key " + keys[keys.length - 1] + " in '" + key + "'");
            }
            current.getAsJsonObject().remove(keys[keys.length - 1]);
        } else {
            if (asObject().get(key) == null) {
                throw new IllegalArgumentException("There is no valid object for key " + key);
            }
            asObject().remove(key);
        }
        return this;
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#fetch(java.lang.String)
     */
    @Override
    public Representation fetch(String key) {
        throwIfNotObject();
        JsonElement root;

        if (key.contains(".")) {
            String[] keys = key.split("\\.");
            if (keys.length == 0) {
                throw new IllegalArgumentException(
                        "Malformed key " + keys + " ; use something like user.school.id");
            }
            String lastKey = keys[0];
            JsonElement current = asObject();
            for (String newKey : keys) {
                if (!current.isJsonObject()) {
                    throw new IllegalArgumentException(
                            "The key " + lastKey + " in '" + key + "' doesn't point to a Json Object");
                }
                ;
                current = current.getAsJsonObject().get(newKey);
                if (current == null) {
                    throw new IllegalArgumentException(
                            "There is no valid object for key " + newKey + "in '" + key + "'");
                }
            }
            root = current;
        } else {
            root = asObject().get(key);
        }

        if (root == null) {
            throw new IllegalArgumentException("There is no valid object for key " + key);
        } else {
            GsonRepresentation fetchedRepresentation = new GsonRepresentation();
            fetchedRepresentation.document = root;
            return fetchedRepresentation;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.Representation#copy()
     */
    @Override
    public Representation copy() {
        String serialization = gson.toJson(this.document);
        JsonElement clone = new JsonParser().parse(serialization);
        GsonRepresentation representation = new GsonRepresentation();
        representation.document = clone;
        return representation;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * io.robusta.rra.representation.Representation#createNewRepresentation(
     * java.lang.Object)
     */
    @Override
    public Representation createNewRepresentation(Object newObject) {
        return new GsonRepresentation(newObject);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * io.robusta.rra.representation.Representation#createNewRepresentation(
     * java.lang.String)
     */
    @Override
    public Representation createNewRepresentation(String json) {
        return new GsonRepresentation(json);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * io.robusta.rra.representation.Representation#createNewRepresentation(
     * java.io.InputStream)
     */
    @Override
    public Representation createNewRepresentation(InputStream inputStream) {
        return new GsonRepresentation(inputStream);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * io.robusta.rra.representation.Representation#createNewRepresentation()
     */
    @Override
    public Representation createNewRepresentation() {
        return new GsonRepresentation();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * io.robusta.rra.representation.JsonRepresentation#addToArray(io.robusta
     * .rra.resource.Resource, boolean)
     */
    @Override
    public Representation addToArray(Resource resource, boolean eager) {
        throwIfNotArray();
        // TODO : to use eager, we must look at ReflectiveTypeAdapterFactory
        // around line 82
        JsonElement element = gson.toJsonTree(resource);
        asArray().add(element);
        return this;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * io.robusta.rra.representation.JsonRepresentation#addToArray(java.lang
     * .Object)
     */
    @Override
    public Representation addToArray(Object value) {
        throwIfNotArray();
        JsonElement element = gson.toJsonTree(value);
        asArray().add(element);
        return this;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * io.robusta.rra.representation.JsonRepresentation#pluck(java.lang.Class,
     * java.lang.String)
     */
    @Override
    public <T> List<T> pluck(Class<T> type, String key) throws RepresentationException {
        throwIfNotArray();
        List<T> result = new ArrayList<T>();
        for (JsonElement elt : asArray()) {
            result.add(get(type, elt));
        }
        return result;
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.JsonRepresentation#isPrimitive()
     */
    @Override
    public boolean isPrimitive() {
        return this.document.isJsonPrimitive();
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.JsonRepresentation#isObject()
     */
    @Override
    public boolean isObject() {
        return this.document.isJsonObject();
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.JsonRepresentation#isBoolean()
     */
    @Override
    public boolean isBoolean() {
        // checking that it' a primitive
        if (this.document.isJsonPrimitive()) {
            String json = this.document.toString();
            return json.equalsIgnoreCase("true") || json.equalsIgnoreCase("false");
        } else {
            return false;
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.JsonRepresentation#isString()
     */
    @Override
    public boolean isString() {
        return isString(this.document);
    }

    /**
     * @param elt
     * @return
     */
    private boolean isString(JsonElement elt) {
        return elt.isJsonPrimitive()
                && (elt.toString().trim().startsWith("\"") || elt.toString().trim().startsWith("'"));
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.JsonRepresentation#isNumber()
     */
    @Override
    public boolean isNumber() {
        return this.document.isJsonPrimitive() && !this.isBoolean() && !this.isString();
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.JsonRepresentation#isArray()
     */
    @Override
    public boolean isArray() {
        return this.document.isJsonArray();
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.JsonRepresentation#isNull()
     */
    @Override
    public boolean isNull() {
        return this.document.isJsonNull();
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.JsonRepresentation#getTypeof()
     */
    @Override
    public JsonType getTypeof() {
        if (this.isString()) {
            return JsonType.STRING;
        } else if (this.isArray()) {
            return JsonType.ARRAY;
        } else if (this.isBoolean()) {
            return JsonType.BOOLEAN;
        } else if (this.isNumber()) {
            return JsonType.NUMBER;
        } else if (this.isNull()) {
            return JsonType.NULL;
        } else if (this.isObject()) {
            return JsonType.OBJECT;
        } else
            throw new IllegalStateException("Can't find the type of this document");
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.JsonRepresentation#createObject()
     */
    @Override
    public Representation<JsonElement> createObject() {
        if (this.document != null) {
            throw new IllegalStateException(
                    "This representation is not Empty. Use createNewRepresentation() to get a new empty representation");
        }
        this.document = new JsonObject();
        return this;
    }

    /*
     * (non-Javadoc)
     * 
     * @see io.robusta.rra.representation.JsonRepresentation#createArray()
     */
    @Override
    public Representation<JsonElement> createArray() {
        if (this.document != null) {
            throw new IllegalStateException(
                    "This representation is not Empty. Use createNewRepresentation() to get a new empty representation");
        }
        this.document = new JsonArray();
        return this;
    }

    /**
     * 
     * @param type
     * @return
     */
    protected JsonType getJsonType(Class type) {
        if (type == Integer.class || type == Long.class || type == Integer.class || type == Integer.class) {
            return JsonType.NUMBER;
        } else if (type == String.class) {

        }
        return null;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return this.document.toString();
    }
}