edu.mit.media.funf.json.JsonUtils.java Source code

Java tutorial

Introduction

Here is the source code for edu.mit.media.funf.json.JsonUtils.java

Source

/**
 * 
 * Funf: Open Sensing Framework
 * Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland.
 * Acknowledgments: Alan Gardner
 * Contact: nadav@media.mit.edu
 * 
 * This file is part of Funf.
 * 
 * Funf is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version.
 * 
 * Funf 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with Funf. If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package edu.mit.media.funf.json;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import android.net.Uri;

import com.google.gson.Gson;
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.JsonPrimitive;

public class JsonUtils {

    private JsonUtils() {
    }

    private static final Comparator<Entry<String, JsonElement>> JSON_OBJECT_ENTRY_SET_COMPARATOR = new Comparator<Map.Entry<String, JsonElement>>() {
        @Override
        public int compare(Entry<String, JsonElement> lhs, Entry<String, JsonElement> rhs) {
            return lhs == null ? (rhs == null ? 0 : -1) : (rhs == null ? 1 : lhs.getKey().compareTo(rhs.getKey()));
        }
    };

    /**
     * Sort all elements in Json objects, to ensure that they are identically serialized.
     * @param el
     * @return
     */
    public static JsonElement deepSort(JsonElement el) {
        if (el == null) {
            return null;
        } else if (el.isJsonArray()) {
            JsonArray sortedArray = new JsonArray();
            for (JsonElement subEl : (JsonArray) el) {
                sortedArray.add(deepSort(subEl));
            }
            return sortedArray;
        } else if (el.isJsonObject()) {
            List<Entry<String, JsonElement>> entrySet = new ArrayList<Entry<String, JsonElement>>(
                    ((JsonObject) el).entrySet());
            Collections.sort(entrySet, JSON_OBJECT_ENTRY_SET_COMPARATOR);
            JsonObject sortedObject = new JsonObject();
            for (Entry<String, JsonElement> entry : entrySet) {
                sortedObject.add(entry.getKey(), deepSort(entry.getValue()));
            }
            return sortedObject;
        } else {
            return el;
        }
    }

    /**
     * Returns a deep copy of the JsonElement.  This is not thread safe.
     * @param el
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T extends JsonElement> T deepCopy(T el) {
        if (el == null) {
            return (T) JsonNull.INSTANCE;
        } else if (el.isJsonArray()) {
            JsonArray array = new JsonArray();
            for (JsonElement subEl : el.getAsJsonArray()) {
                array.add(deepCopy(subEl));
            }
            return (T) array;
        } else if (el.isJsonObject()) {
            JsonObject object = new JsonObject();
            for (Map.Entry<String, JsonElement> entry : el.getAsJsonObject().entrySet()) {
                object.add(entry.getKey(), deepCopy(entry.getValue()));
            }
            return (T) object;
        } else {
            return (T) el;
        }
    }

    /**
     * Return an immutable JsonElement.  Either IJsonObject, IJsonArray, or other immutable JsonPrimitive.
     * @param el
     * @return
     */
    public static JsonElement immutable(JsonElement el) {
        if (el instanceof JsonObject) {
            return new IJsonObject(el.getAsJsonObject());
        } else if (el instanceof JsonArray) {
            return new IJsonArray(el.getAsJsonArray());
        } else if (el instanceof JsonPrimitive && el.getAsJsonPrimitive().isNumber()) {
            // Ensure that all LazilyParsedNumbers have been parsed into a consistent Number type.
            // Otherwise hash codes are not consistent, because LazilyParsedNumbers are never seen as integral.
            return new JsonPrimitive(el.getAsBigDecimal());
        }
        return el;
    }

    /**
     * In place copy of one objects values onto another, with option to replace existing values in copy.
     * @param source
     * @param destination
     * @param replace
     */
    public static void deepCopyOnto(JsonObject source, JsonObject destination, boolean replace) {
        if (source == null || destination == null) {
            throw new RuntimeException(
                    "Both source and destination must exist while copying values from one to another.");
        }
        JsonObject sourceCopy = new JsonParser().parse(source.toString()).getAsJsonObject(); // Defensive copy to ensure the source is never modified
        deepCopyOnto(sourceCopy, destination, replace, true);
    }

    private static void deepCopyOnto(JsonObject source, JsonObject destination, boolean replace, boolean initial) {
        for (Map.Entry<String, JsonElement> sourceVal : source.entrySet()) {
            if (replace || !destination.has(sourceVal.getKey())) {
                String key = sourceVal.getKey();
                JsonElement value = sourceVal.getValue();
                if (value.isJsonObject() && destination.has(key) && destination.get(key).isJsonObject()) {
                    deepCopyOnto(value.getAsJsonObject(), destination.get(key).getAsJsonObject(), replace, false);
                } else {
                    destination.add(key, value);
                }
            }
        }
    }

    public static final Gson GSON = new Gson();

    public static final String JSON_SCHEME = "json";

    /**
     * Transform json into an immutable Uri
     * @param el
     * @return
     */
    public static Uri toUri(JsonElement el) {
        return new Uri.Builder().scheme(JSON_SCHEME).appendPath(immutable(el).toString()).build();
    }

    /**
     * Parse json data from a json:// uri
     * @param uri
     * @return
     */
    public static JsonElement fromUri(Uri uri) {
        return JSON_SCHEME.equals(uri.getScheme()) ? new JsonParser().parse(uri.getPath()) : null;
    }
}