JSONObject's keySet should iterate in an oder that is consistent between hosted and web mode. This was being caused by the evil iterate-over-HashMap pattern.
Review by: jat (desk)
git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@4607 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/json/client/JSONObject.java b/user/src/com/google/gwt/json/client/JSONObject.java
index 6fd985d..17233ff 100644
--- a/user/src/com/google/gwt/json/client/JSONObject.java
+++ b/user/src/com/google/gwt/json/client/JSONObject.java
@@ -15,11 +15,14 @@
*/
package com.google.gwt.json.client;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
+import java.util.AbstractSet;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
-import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -39,7 +42,7 @@
private final JavaScriptObject jsObject;
public JSONObject() {
- jsObject = JavaScriptObject.createObject();
+ this(JavaScriptObject.createObject());
}
/**
@@ -110,9 +113,23 @@
* Returns the set of properties defined on this JSONObject.
*/
public Set<String> keySet() {
- HashSet<String> keySet = new HashSet<String>();
- addAllKeys(keySet);
- return 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;
+ }
+ };
}
/**
@@ -138,7 +155,8 @@
* Determines the number of properties on this object.
*/
public int size() {
- return keySet().size();
+ // Must always recheck due to foreign changes. :(
+ return computeSize();
}
/**
@@ -152,8 +170,7 @@
StringBuffer sb = new StringBuffer();
sb.append("{");
boolean first = true;
- List<String> keys = new ArrayList<String>();
- addAllKeys(keys);
+ String[] keys = computeKeys();
for (String key : keys) {
if (first) {
first = false;
@@ -180,6 +197,34 @@
}
}-*/;
+ 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) {
+ 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) {
+ ++size;
+ }
+ return size;
+ }-*/;
+
private native JSONValue get0(String key) /*-{
var v = this.@com.google.gwt.json.client.JSONObject::jsObject[key];
var func = @com.google.gwt.json.client.JSONParser::typeMap[typeof v];