| /* | |
| * Copyright 2008 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.GWT; | |
| import com.google.gwt.core.client.JavaScriptObject; | |
| import com.google.gwt.core.client.JsonUtils; | |
| import java.util.AbstractSet; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.Collection; | |
| import java.util.Iterator; | |
| import java.util.List; | |
| import java.util.Set; | |
| /** | |
| * Represents a JSON object. A JSON object consists of a set of properties. | |
| */ | |
| public class JSONObject extends JSONValue { | |
| /** | |
| * Called from {@link #getUnwrapper()}. | |
| */ | |
| private static JavaScriptObject unwrap(JSONObject value) { | |
| return value.jsObject; | |
| } | |
| private final JavaScriptObject jsObject; | |
| public JSONObject() { | |
| this(JavaScriptObject.createObject()); | |
| } | |
| /** | |
| * Creates a new JSONObject from the supplied JavaScript value. | |
| */ | |
| public JSONObject(JavaScriptObject jsValue) { | |
| jsObject = jsValue; | |
| } | |
| /** | |
| * Tests whether or not this JSONObject contains the specified property. | |
| * | |
| * @param key the property to search for | |
| * @return <code>true</code> if the JSONObject contains the specified property | |
| */ | |
| public native boolean containsKey(String key) /*-{ | |
| return key in this.@com.google.gwt.json.client.JSONObject::jsObject; | |
| }-*/; | |
| /** | |
| * Returns <code>true</code> if <code>other</code> is a {@link JSONObject} | |
| * wrapping the same underlying object. | |
| */ | |
| @Override | |
| public boolean equals(Object other) { | |
| if (!(other instanceof JSONObject)) { | |
| return false; | |
| } | |
| return jsObject.equals(((JSONObject) other).jsObject); | |
| } | |
| /** | |
| * Gets the JSONValue associated with the specified property. | |
| * | |
| * @param key the property to access | |
| * @return the value of the specified property, or <code>null</code> if the | |
| * property does not exist | |
| * @throws NullPointerException if key is <code>null</code> | |
| */ | |
| public JSONValue get(String key) { | |
| if (key == null) { | |
| throw new NullPointerException(); | |
| } | |
| return get0(key); | |
| } | |
| /** | |
| * Returns the underlying JavaScript object that this object wraps. | |
| */ | |
| public JavaScriptObject getJavaScriptObject() { | |
| return jsObject; | |
| } | |
| @Override | |
| public int hashCode() { | |
| return jsObject.hashCode(); | |
| } | |
| /** | |
| * Returns <code>this</code>, as this is a JSONObject. | |
| */ | |
| @Override | |
| public JSONObject isObject() { | |
| return this; | |
| } | |
| /** | |
| * Returns the set of properties defined on this JSONObject. The returned set | |
| * is immutable. | |
| */ | |
| public Set<String> keySet() { | |
| final String[] keys = computeKeys(); | |
| return new AbstractSet<String>() { | |
| @Override | |
| public boolean contains(Object o) { | |
| return (o instanceof String) && containsKey((String) o); | |
| } | |
| @Override | |
| public Iterator<String> iterator() { | |
| return Arrays.asList(keys).iterator(); | |
| } | |
| @Override | |
| public int size() { | |
| return keys.length; | |
| } | |
| }; | |
| } | |
| /** | |
| * Assign the specified property to the specified value in this JSONObject. If | |
| * the property already has an associated value, it is overwritten. | |
| * | |
| * @param key the property to assign | |
| * @param jsonValue the value to assign | |
| * @return the previous value of the property, or <code>null</code> if the | |
| * property did not exist | |
| * @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); | |
| put0(key, jsonValue); | |
| return previous; | |
| } | |
| /** | |
| * Determines the number of properties on this object. | |
| */ | |
| public int size() { | |
| // Must always recheck due to foreign changes. :( | |
| return computeSize(); | |
| } | |
| /** | |
| * 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 | |
| */ | |
| @Override | |
| public String toString() { | |
| StringBuffer sb = new StringBuffer(); | |
| sb.append("{"); | |
| boolean first = true; | |
| String[] keys = computeKeys(); | |
| for (String key : keys) { | |
| if (first) { | |
| first = false; | |
| } else { | |
| sb.append(", "); | |
| } | |
| sb.append(JsonUtils.escapeValue(key)); | |
| sb.append(":"); | |
| sb.append(get(key)); | |
| } | |
| sb.append("}"); | |
| return sb.toString(); | |
| } | |
| @Override | |
| native JavaScriptObject getUnwrapper() /*-{ | |
| return @com.google.gwt.json.client.JSONObject::unwrap(Lcom/google/gwt/json/client/JSONObject;); | |
| }-*/; | |
| private native void addAllKeys(Collection<String> s) /*-{ | |
| var jsObject = this.@com.google.gwt.json.client.JSONObject::jsObject; | |
| for (var key in jsObject) { | |
| if (jsObject.hasOwnProperty(key)) { | |
| s.@java.util.Collection::add(Ljava/lang/Object;)(key); | |
| } | |
| } | |
| }-*/; | |
| private String[] computeKeys() { | |
| if (GWT.isScript()) { | |
| return computeKeys0(new String[0]); | |
| } else { | |
| List<String> result = new ArrayList<String>(); | |
| addAllKeys(result); | |
| return result.toArray(new String[result.size()]); | |
| } | |
| } | |
| private native String[] computeKeys0(String[] result) /*-{ | |
| var jsObject = this.@com.google.gwt.json.client.JSONObject::jsObject; | |
| var i = 0; | |
| for (var key in jsObject) { | |
| if (jsObject.hasOwnProperty(key)) { | |
| result[i++] = key; | |
| } | |
| } | |
| return result; | |
| }-*/; | |
| private native int computeSize() /*-{ | |
| var jsObject = this.@com.google.gwt.json.client.JSONObject::jsObject; | |
| var size = 0; | |
| for (var key in jsObject) { | |
| if (jsObject.hasOwnProperty(key)) { | |
| ++size; | |
| } | |
| } | |
| return size; | |
| }-*/; | |
| private native JSONValue get0(String key) /*-{ | |
| var jsObject = this.@com.google.gwt.json.client.JSONObject::jsObject; | |
| var v; | |
| // In Firefox, jsObject.hasOwnProperty(key) requires a primitive string | |
| key = String(key); | |
| if (jsObject.hasOwnProperty(key)) { | |
| v = jsObject[key]; | |
| } | |
| var func = @com.google.gwt.json.client.JSONParser::typeMap[typeof v]; | |
| var ret = func ? func(v) : @com.google.gwt.json.client.JSONParser::throwUnknownTypeException(Ljava/lang/String;)(typeof v); | |
| return ret; | |
| }-*/; | |
| private native void put0(String key, JSONValue value) /*-{ | |
| if (value) { | |
| var func = value.@com.google.gwt.json.client.JSONValue::getUnwrapper()(); | |
| this.@com.google.gwt.json.client.JSONObject::jsObject[key] = func(value); | |
| } else { | |
| delete this.@com.google.gwt.json.client.JSONObject::jsObject[key]; | |
| } | |
| }-*/; | |
| } |