JsonObject.java

/***************************************************************************
   Copyright 2014 Emily Estes

   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 net.metanotion.json;


import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Set;

import net.metanotion.util.Dictionary;
import net.metanotion.util.DictionaryIndex;

/** This class represents a JSON object (set of key/value pairs). */
public final class JsonObject implements Dictionary<String,Object>, DictionaryIndex<String,Object>, Json {
	private final HashMap<String,Object> obj = new HashMap<>();

	/** Retrive the value stored under the key.
		@param key The key to lookup.
		@return The value mapped to the key or null if there is no such value(or null if the key is mapped to null).
	*/
	@Override public Object get(final String key) { return obj.get(key); }

	/** A set of the keys in this JSON object.
		@return The set of keys in this object.
	*/
	@Override public Set<String> keySet() { return obj.keySet(); }

	/** Associate the value provided with the key provided.
		@param key the key to map to the object.
		@param val The value to store.
		@return the value previously associated with the key or null if there was no value.
		@throws IllegalArgumentException if the value is of the wrong type to store in a JSON object.
	*/
	public Object put(final String key, final Object val) {
		if(	(val == null)
			|| (val instanceof JsonObject)
			|| (val instanceof JsonArray)
			|| (val instanceof Number)
			|| (val instanceof Boolean)
			|| (val instanceof String)) {
			return obj.put(key, val);
		} else {
			throw new IllegalArgumentException("Invalid type to add to this JsonObject");
		}
	}

	/** Remove the key mapping from this JSON object.
		@param key The key to remove.
		@return the value previously associated with the key or null if there was no value.
	*/
	public Object remove(final String key) { return obj.remove(key); }

	/** Return the length of the array.
		@return The number of keys mapped in this object.
	*/
	public int size() { return obj.size(); }

	@Override public int hashCode() { return obj.hashCode(); }
	@Override public boolean equals(final Object o) {
		if(!(o instanceof JsonObject)) { return false; }
		return ((JsonObject) o).obj.equals(obj);
	}

	/** Produce a JSON encoded string representing the values contained in this instance.
		@return a JSON encoded string representing this instance.
	*/
	@Override public String toString() {
		final StringWriter out = new StringWriter();
		(new JsonWriter(out)).write(this);
		return out.toString();
	}

	private static final StreamingParser parser = new StreamingParser();

	/** Parse a JSON encoded string and produce an instance of JsonObject from it.
		@param json The JSON encoded string to read.
		@return An instance of JsonObject representing the data encoded in the string.
		@throws RuntimeException if the string does not represent a JSON object.
		@throws IOException if there is an I/O reading the string.
	*/
	public static JsonObject read(final String json) throws IOException { return read(new StringReader(json)); }

	/** Parse a JSON encoded stream and produce an instance of JsonObject from it.
		@param json The stream JSON encoded data to read.
		@return An instance of JsonObject representing the data encoded in the string.
		@throws RuntimeException if the stream does not encode a JSON object.
		@throws IOException if there is an I/O reading the stream.
	*/
	public static JsonObject read(final Reader json) throws IOException {
		return parser.parse(json, new JsonReader<JsonObject>());
	}
}