| /* |
| * 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(""); |
| }-*/; |
| } |