| /* |
| * 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() { |
| StringBuilder sb = new StringBuilder("{"); |
| 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]; |
| } |
| }-*/; |
| } |