br.com.thiaguten.contrib.JsonContrib.java Source code

Java tutorial

Introduction

Here is the source code for br.com.thiaguten.contrib.JsonContrib.java

Source

/*
 * Copyright 2013-2014 the original author or authors.
 * 
 * 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
 * 
 *     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 br.com.thiaguten.contrib;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;

/**
 * This class helps with some more features for converting and manipulating JSON using GSON API.
 *
 * @author Thiago Gutenberg C. da Costa
 * @author Leandro Ozelame M. Ferreira
 * @since 1.0.0
 */
public abstract class JsonContrib {

    private static final Gson GSON_INSTANCE;
    private static final AtomicInteger COUNTER;

    static {
        GSON_INSTANCE = new GsonBuilder().serializeNulls().setDateFormat("yyyy-MM-dd").create();
        COUNTER = new AtomicInteger(0);
    }

    public static Gson getGsonInstance() {
        return GSON_INSTANCE;
    }

    /**
     * @param object the specified object to be serialized
     * @return Json representation of {@code object}
     * @see com.google.gson.Gson#toJson(Object)
     */
    public static String objectToJson(Object object) {
        return getGsonInstance().toJson(object);
    }

    /**
     * @param json     the string from which the object is to be deserialized
     * @param classOfT the class of T
     * @param <T>      the type of the desired object
     * @return an object of type T from the string
     * @see com.google.gson.Gson#fromJson(String, Class)
     */
    public static <T> T jsonToObject(String json, Class<T> classOfT) {
        return getGsonInstance().fromJson(json, classOfT);
    }

    /**
     * @param object the object for which Json representation is to be created setting for Gson
     * @return Json representation of {@code object}
     * @see com.google.gson.Gson#toJsonTree(Object)
     */
    public static JsonElement objectToJsonElementTree(Object object) {
        return getGsonInstance().toJsonTree(object);
    }

    /**
     * Parses the object into its equivalent JsonElement representation.
     * <p/>
     * Will be thrown {@code JsonSyntaxException} if the specified object is an instance of String and
     *
     * @param object the specified object to be parsed
     * @return JsonElement representation of specified object
     * //@throws JsonSyntaxException
     */
    public static JsonElement parseObject(Object object) /*throws JsonSyntaxException*/ {
        if (object != null && object instanceof String) {
            try {
                return new JsonParser().parse((String) object);
            } catch (JsonSyntaxException e) {
                return null;
            }
        } else {
            return objectToJsonElementTree(object);
        }
    }

    /**
     * Checks if a string is a valid representation of a JSON
     *
     * @param json string to be checked
     * @return true if it is valid if not otherwise
     */
    public static boolean isJsonValid(String json) {
        return parseObject(json) != null;
    }

    /**
     * Appends value to json
     *
     * @param json  string json which will be modified
     * @param value value that will be appended
     * @return the specified JSON string with appended value
     */
    public static String appendValueToJson(String json, Object value) {
        return appendValueToJson(json, null, value);
    }

    /**
     * Appends key and/or value to json
     *
     * @param json  string json which will be modified
     * @param key   key that will be appended
     * @param value value that will be appended
     * @return the specified JSON string with appended key and/or value
     */
    public static String appendValueToJson(String json, String key, Object value) {
        JsonElement jsonElement = parseObject(json);

        if (jsonElement != null) {
            if (jsonElement.isJsonPrimitive()) {
                JsonArray jsonArray = new JsonArray();
                jsonArray.add(jsonElement);
                jsonArray.add(objectToJsonElementTree(value));
                return jsonArray.toString();
            } else if (jsonElement.isJsonObject()) {
                if (key == null) {
                    throw new IllegalArgumentException(
                            "to append some value into a JsonObject the 'key' parameter must not be null");
                }
                JsonObject jsonObject = (JsonObject) jsonElement;
                jsonObject.add(key, objectToJsonElementTree(value));
                return jsonObject.toString();
            } else if (jsonElement.isJsonArray()) {
                JsonArray jsonArray = (JsonArray) jsonElement;
                jsonArray.add(objectToJsonElementTree(value));
                return jsonArray.toString();
            }
        }
        return getJsonElementAsString(jsonElement);
    }

    /**
     * Converts an object into a {@code JsonElement} and search values by their keys
     *
     * @param object object you wish to obtain the value
     * @param keys   keys to search on {@code JsonElement}
     * @return list of occurrences found
     */
    public static List<Object> findValuesByKeys(Object object, String... keys) {
        JsonElement jsonElement = parseObject(object);

        List<Object> occurrencesFound = null;
        if (jsonElement != null && keys != null) {
            occurrencesFound = new ArrayList<Object>();
            for (String key : keys) {
                deepJsonSearchByKeyToList(key, jsonElement, occurrencesFound);
            }
        }
        return occurrencesFound;
    }

    /**
     * Converts an object into a {@code JsonElement}, search values by their keys and returns first occurrence found
     *
     * @param object object you wish to obtain the value
     * @param keys   keys to search on {@code JsonElement}
     * @return first occurrence found
     */
    public static String findFirstValueByKeys(Object object, String... keys) {
        List<Object> occurrencesFound = findValuesByKeys(object, keys);
        if (occurrencesFound != null && !occurrencesFound.isEmpty()) {
            return getJsonElementAsString(parseObject(occurrencesFound.get(0)));
        }
        return null;
    }

    /**
     * Converts an object into a {@code JsonElement}, search values by their keys and returns first not null occurrence found
     *
     * @param object object you wish to obtain the value
     * @param keys   keys to search on {@code JsonElement}
     * @return first not null occurrence found
     */
    public static String findFirstNotNullValueByKeys(Object object, String... keys) {
        List<Object> occurrencesFound = findValuesByKeys(object, keys);
        if (occurrencesFound != null && !occurrencesFound.isEmpty()) {
            for (Object obj : occurrencesFound) {
                JsonElement jsonElement = parseObject(obj);
                if (jsonElement != null && !jsonElement.isJsonNull()) {
                    return getJsonElementAsString(jsonElement);
                }
            }
        }
        return null;
    }

    /**
     * Converts the object to json string without the complexity
     * of relational hierarchy between them, creating a json "flatten".
     *
     * @param object object you wish to converts into a json flatten
     * @return flattened json
     */
    public static String plainJson(Object object) {
        JsonElement jsonElement = parseObject(object);

        if (jsonElement != null) {
            if (jsonElement.isJsonObject()) {
                JsonObject jsonObjectFlattened = new JsonObject();
                deepJsonObjectSearchToJsonObjectFlattened((JsonObject) jsonElement, jsonObjectFlattened);
                return jsonObjectFlattened.toString();
            } else if (jsonElement.isJsonArray()) {
                JsonArray jsonArrayFlattened = new JsonArray();
                deepJsonArraySearchToJsonArrayFlattened((JsonArray) jsonElement, jsonArrayFlattened);
                return jsonArrayFlattened.toString();
            }
        }
        return getJsonElementAsString(jsonElement);
    }

    /**
     * Converts the json string to an list of objects.
     * <p/>
     * The parameter {@code flatten} determines if will return a list without the complexity
     * of relational hierarchy between the objects or not
     *
     * @param json    string json you wish to converts into a list
     * @param flatten true to return a flat list, false otherwise
     * @return list of objects
     */
    public static List<Object> jsonToList(String json, boolean flatten) {
        List<JsonElement> jsonElementList = jsonToJsonElementList(json, flatten);

        List<Object> objectList = null;
        if (jsonElementList != null && !jsonElementList.isEmpty()) {
            objectList = new ArrayList<Object>();
            for (JsonElement jsonElement : jsonElementList) {
                objectList.add(getJsonElementAsString(jsonElement));
            }
        }
        return objectList;
    }

    /**
     * Converts the json string to an flattened list of objects
     *
     * @param json string json you wish to converts into a list
     * @return list of objects
     */
    public static List<Object> jsonToList(String json) {
        return jsonToList(json, true);
    }

    //************************** PRIVATE METHODS **************************//

    private static void deepJsonArraySearchToJsonArrayFlattened(JsonArray jsonArray, JsonArray jsonArrayFlattened) {
        if (jsonArray == null || jsonArrayFlattened == null) {
            throw new IllegalArgumentException("JsonArray and/or JsonArrayFlattened parameter(s) must not be null");
        }

        Iterator<JsonElement> iterator = jsonArray.iterator();
        while (iterator.hasNext()) {
            JsonElement value = iterator.next();

            if (value.isJsonObject()) {
                // Creates new flattened JsonObject instance.
                JsonObject jsonObjectFlattened = new JsonObject();
                // Iterates recursively in JsonObject (value), checking content and populating the flattened JsonObject instance.
                deepJsonObjectSearchToJsonObjectFlattened((JsonObject) value, jsonObjectFlattened);
                // Adds the flattened JsonObject instance in the flattened JsonArray instance.
                jsonArrayFlattened.add(jsonObjectFlattened);
            } else if (value.isJsonArray()) {
                deepJsonArraySearchToJsonArrayFlattened((JsonArray) value, jsonArrayFlattened);
            } else {
                jsonArrayFlattened.add(value);
            }
        }
    }

    private static void deepJsonObjectSearchToJsonObjectFlattened(JsonObject jsonObject,
            JsonObject jsonObjectFlattened) {
        if (jsonObject == null || jsonObjectFlattened == null) {
            throw new IllegalArgumentException(
                    "JsonObject and/or JsonObjectFlattened parameter(s) must not be null");
        }

        for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
            String key = entry.getKey();
            JsonElement value = entry.getValue();

            if (value.isJsonObject()) {
                deepJsonObjectSearchToJsonObjectFlattened((JsonObject) value, jsonObjectFlattened);
            } else if (value.isJsonArray()) {
                // Creates new flattened JsonArray instance.
                JsonArray jsonArray = new JsonArray();
                // Iterates recursively in JsonArray (value), checking content and populating the flattened JsonArray instance.
                deepJsonArraySearchToJsonArrayFlattened((JsonArray) value, jsonArray);
                // Adds the flattened JsonArray instance in the flattened JsonObject instance.
                jsonObjectFlattened.add(key, jsonArray);
            } else {
                // FIXME - WORKAROUND
                // Attention: A map can not contain duplicate keys. So, the
                // duplicate key is concatenated with a counter, to avoid data
                // loss. I could not think of anything better yet.
                if (jsonObjectFlattened.has(key)) {
                    jsonObjectFlattened.add(key + COUNTER.getAndIncrement(), value);
                } else {
                    jsonObjectFlattened.add(key, value);
                }
            }
        }
    }

    private static void deepJsonSearchToList(JsonElement jsonElement, List<JsonElement> jsonElementList) {
        if (jsonElement != null && jsonElementList != null) {
            if (jsonElement.isJsonObject()) {
                for (Map.Entry<String, JsonElement> entry : ((JsonObject) jsonElement).entrySet()) {
                    deepJsonSearchToList(entry.getValue(), jsonElementList);
                }
            } else if (jsonElement.isJsonArray()) {
                Iterator<JsonElement> iterator = ((JsonArray) jsonElement).iterator();
                while (iterator.hasNext()) {
                    deepJsonSearchToList(iterator.next(), jsonElementList);
                }
            } else {
                jsonElementList.add(jsonElement);
            }
        }
    }

    private static void deepJsonSearchByKeyToList(String desiredKey, JsonElement jsonElement,
            List<Object> jsonElementList) {
        if (desiredKey != null && jsonElement != null && jsonElementList != null) {
            if (jsonElement.isJsonObject()) {
                for (Map.Entry<String, JsonElement> entry : ((JsonObject) jsonElement).entrySet()) {
                    String key = entry.getKey();
                    JsonElement value = entry.getValue();

                    if (key.equalsIgnoreCase(desiredKey)) {
                        jsonElementList.add(getJsonElementAsString(value));
                    }

                    deepJsonSearchByKeyToList(desiredKey, entry.getValue(), jsonElementList);
                }
            } else if (jsonElement.isJsonArray()) {
                Iterator<JsonElement> iterator = ((JsonArray) jsonElement).iterator();
                while (iterator.hasNext()) {
                    deepJsonSearchByKeyToList(desiredKey, iterator.next(), jsonElementList);
                }
            }
        }
    }

    private static List<JsonElement> jsonToJsonElementList(String json, boolean flatten) {
        JsonElement jsonElement = parseObject(json);

        List<JsonElement> elements = null;
        if (jsonElement != null) {
            boolean isJsonObject = jsonElement.isJsonObject();
            boolean isJsonArray = jsonElement.isJsonArray();

            elements = new ArrayList<JsonElement>();

            // Only instances of 'JsonArray' or 'JsonObject' can be flattened
            if (isJsonArray || isJsonObject) {
                if (flatten) {
                    deepJsonSearchToList(jsonElement, elements);
                } else {
                    if (isJsonObject) {
                        for (Map.Entry<String, JsonElement> entry : ((JsonObject) jsonElement).entrySet()) {
                            elements.add(entry.getValue());
                        }
                    } else {
                        Iterator<JsonElement> iterator = ((JsonArray) jsonElement).iterator();
                        while (iterator.hasNext()) {
                            elements.add(iterator.next());
                        }
                    }
                }
            } else {
                elements.add(jsonElement);
            }
        }
        return elements;
    }

    private static String getJsonElementAsString(JsonElement jsonElement) {
        if (jsonElement == null) {
            return JsonNull.INSTANCE.toString();
        }
        if (jsonElement.isJsonPrimitive()) {
            return jsonElement.getAsString();
        }
        return jsonElement.toString();
    }
}