blob: 8776f990718ed0b1f676016862eb0fbeec51eaf4 [file] [log] [blame]
/*
* Copyright 2007 Google Inc.
*
* 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 com.google.gwt.json.client;
import com.google.gwt.core.client.JavaScriptObject;
import java.util.HashSet;
import java.util.Set;
/**
* Represents a JSON object. A JSON object is a map of string-based keys onto a
* set of {@link com.google.gwt.json.client.JSONValue} objects.
*/
public class JSONObject extends JSONValue {
private static native void addAllKeysFromJavascriptObject(Set s,
JavaScriptObject javaScriptObject) /*-{
for(var key in javaScriptObject) {
s.@java.util.Set::add(Ljava/lang/Object;)(key);
}
}-*/;
private static native boolean containsBack(JavaScriptObject backStore, String key) /*-{
key = String(key);
return Object.prototype.hasOwnProperty.call(backStore, key);
}-*/;
private static native JSONValue getFront(JavaScriptObject frontStore, String key) /*-{
key = String(key);
return Object.prototype.hasOwnProperty.call(frontStore, key) ? frontStore[key] : null;
}-*/;
private static native void putFront(JavaScriptObject frontStore, String key,
JSONValue jsonValue) /*-{
frontStore[String(key)] = jsonValue;
}-*/;
private static native JavaScriptObject removeBack(JavaScriptObject backStore, String key) /*-{
key = String(key);
var result = backStore[key];
delete backStore[key];
if (typeof result != 'object') {
result = Object(result);
}
return result;
}-*/;
private final JavaScriptObject backStore;
private final JavaScriptObject frontStore = JavaScriptObject.createObject();
public JSONObject() {
backStore = JavaScriptObject.createObject();
}
/**
* Creates a new JSONObject from the supplied JavaScript value.
*/
public JSONObject(JavaScriptObject jsValue) {
backStore = jsValue;
}
/**
* Tests whether or not this JSONObject contains the specified key.
*
* We use Object.hasOwnProperty here to verify that a given key is specified
* on this object rather than a superclass (such as standard properties
* defined on Object).
*
* @param key the key to search for
* @return <code>true</code> if the JSONObject contains the specified key
*/
public boolean containsKey(String key) {
return get(key) != null;
}
/**
* Gets the JSONValue associated with the specified key.
*
* We use Object.hasOwnProperty here to verify that a given key is specified
* on this object rather than a superclass (such as standard properties
* defined on Object).
*
* @param key the key to search for
* @return if found, the value associated with the specified key, or
* <code>null</code> otherwise
*/
public JSONValue get(String key) {
if (key == null) {
return null;
}
JSONValue result = getFront(frontStore, key);
if (result == null && containsBack(backStore, key)) {
JavaScriptObject jso = removeBack(backStore, key);
result = JSONParser.buildValue(jso);
putFront(frontStore, key, result);
}
return result;
}
/**
* Returns <code>this</code>, as this is a JSONObject.
*/
public JSONObject isObject() {
return this;
};
/**
* Returns keys for which this JSONObject has associations.
*
* @return array of keys for which there is a value
*/
public Set keySet() {
Set keySet = new HashSet();
addAllKeysFromJavascriptObject(keySet, frontStore);
addAllKeysFromJavascriptObject(keySet, backStore);
return keySet;
}
/**
* Maps the specified key to the specified value in this JSONObject. If the
* specified key already has an associated value, it is overwritten.
*
* @param key the key to associate with the specified value
* @param jsonValue the value to associate with this key
* @return if one existed, the previous value associated with the key, or
* <code>null</code> otherwise
* @throws NullPointerException if key is <code>null</code>
*/
public JSONValue put(String key, JSONValue jsonValue) {
if (key == null) {
throw new NullPointerException();
}
JSONValue previous = get(key);
putFront(frontStore, key, jsonValue);
return previous;
}
/**
* Determines the number of keys on this object.
*/
public int size() {
return keySet().size();
}
/**
* Converts a JSONObject into a JSON representation that can be used to
* communicate with a JSON service.
*
* @return a JSON string representation of this JSONObject instance
*/
public native String toString() /*-{
for (var key in this.@com.google.gwt.json.client.JSONObject::backStore) {
// Wrap everything in backStore so that frontStore is canonical.
this.@com.google.gwt.json.client.JSONObject::get(Ljava/lang/String;)(key);
}
var out = [];
out.push("{");
var first = true;
for (var key in this.@com.google.gwt.json.client.JSONObject::frontStore) {
if(first) {
first = false;
} else {
out.push(", ");
}
var subObj =
(this.@com.google.gwt.json.client.JSONObject::frontStore[key]).
@com.google.gwt.json.client.JSONValue::toString()();
out.push("\"");
out.push(key);
out.push("\":");
out.push(subObj);
}
out.push("}")
return out.join("");
}-*/;
}