Modified:
/trunk/gwt-rpc-plus/gwt/com/dotspots/rpcplus/client/codec/impl/NativeJson.java
/trunk/gwt-rpc-plus/test/gwt-test/com/dotspots/rpcplus/test/client/TestJsonTransport.java
=======================================
---
/trunk/gwt-rpc-plus/gwt/com/dotspots/rpcplus/client/codec/impl/NativeJson.java
Mon Feb 8 16:06:57 2010
+++
/trunk/gwt-rpc-plus/gwt/com/dotspots/rpcplus/client/codec/impl/NativeJson.java
Fri Apr 2 09:36:13 2010
@@ -12,7 +12,9 @@
private final JavaScriptObject wnd;
public static native boolean isSupported(JavaScriptObject window) /*-{
- return ("JSON" in window) && ("stringify" in window.JSON) && ("parse" in
window.JSON);
+ return ("JSON" in window) && ("stringify" in window.JSON) && ("parse" in
window.JSON)
+ // Make sure the page isn't using an ancient (circa-2005) version of JSON
+ && (window.JSON.stringify([1,,1]) == "[1,null,1]");
}-*/;
public NativeJson(JavaScriptObject wnd) {
=======================================
---
/trunk/gwt-rpc-plus/test/gwt-test/com/dotspots/rpcplus/test/client/TestJsonTransport.java
Thu Oct 29 00:34:47 2009
+++
/trunk/gwt-rpc-plus/test/gwt-test/com/dotspots/rpcplus/test/client/TestJsonTransport.java
Fri Apr 2 09:36:13 2010
@@ -93,6 +93,24 @@
run(decoder, encoder);
}
}
+
+ /**
+ * Some sites use an ancient version of Crockford's JSON script that
breaks on [1,,1].
+ */
+ public void testNativeJsonWithBustedStringifier() throws
JsonParseException {
+ try {
+ addBustedJsonArrayStringifier();
+
+ if (NativeJson.isSupported(getWindow())) {
+ NativeJson decoder = new NativeJson(getWindow());
+ NativeJson encoder = new NativeJson(getWindow());
+
+ run(decoder, encoder);
+ }
+ } finally {
+ removeBustedJsonArrayStringifier();
+ }
+ }
public void testUnevalJsonEncoder() throws JsonParseException {
if (UnevalJsonEncoder.isSupported(getWindow())) {
@@ -130,6 +148,17 @@
assertEquals(2, result.size());
assertEquals(0L, list.get(0));
assertEquals(0xffff0000ffff0000L, list.get(1));
+
+ // Test a list with a hole in it
+ list.set(3, 2);
+ text = encoder.encode(list);
+ result = decoder.decode(text).cast();
+
+ assertEquals(4, result.size());
+ assertEquals(0L, list.get(0));
+ assertEquals(0xffff0000ffff0000L, list.get(1));
+ assertEquals(0L, list.get(2));
+ assertEquals(2, list.get(3));
}
/**
@@ -208,6 +237,361 @@
return "com.dotspots.rpcplus.test.Test";
}
+ private native void removeBustedJsonArrayStringifier() /*-{
+ if ($wnd.__oldJSON) {
+ delete $wnd.__oldJSON;
+ } else {
+ $wnd.JSON = $wnd.__oldJSON;
+ }
+ }-*/;
+
+ // JSON code from
http://i.usatoday.net/_common/_scripts/_community/directapi/json.js
+ // Google Plugin For Eclipse is eating the formatting here.
+ private native void addBustedJsonArrayStringifier() /*-{
+ $wnd.__oldJSON = $wnd.JSON;
+ $wnd.JSON = function () {
+ var m = {
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ s = {
+ 'boolean': function (x) {
+ return String(x);
+ },
+ number: function (x) {
+ return isFinite(x) ? String(x) : 'null';
+ },
+ string: function (x) {
+ if (/["\\\x00-\x1f]/.test(x)) {
+ x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
+ var c = m[b];
+ if (c) {
+ return c;
+ }
+ c = b.charCodeAt();
+ return '\\u00' +
+ Math.floor(c / 16).toString(16) +
+ (c % 16).toString(16);
+ });
+ }
+ return '"' + x + '"';
+ },
+ object: function (x) {
+ if (x) {
+ var a = [], b, f, i, l, v;
+ if (x instanceof Array) {
+ a[0] = '[';
+ l = x.length;
+ for (i = 0; i < l; i += 1) {
+ v = x[i];
+ f = s[typeof v];
+ if (f) {
+ v = f(v);
+ if (typeof v == 'string') {
+ if (b) {
+ a[a.length] = ',';
+ }
+ a[a.length] = v;
+ b = true;
+ }
+ }
+ }
+ a[a.length] = ']';
+ } else if (x instanceof Object) {
+ a[0] = '{';
+ for (i in x) {
+ v = x[i];
+ f = s[typeof v];
+ if (f) {
+ v = f(v);
+ if (typeof v == 'string') {
+ if (b) {
+ a[a.length] = ',';
+ }
+ a.push(s.string(i), ':', v);
+ b = true;
+ }
+ }
+ }
+ a[a.length] = '}';
+ } else {
+ return;
+ }
+ return a.join('');
+ }
+ return 'null';
+ }
+ };
+ return {
+ copyright: '(c)2005 JSON.org',
+ license: 'http://www.crockford.com/JSON/license.html',
+ stringify: function (v) {
+ var f = s[typeof v];
+ if (f) {
+ v = f(v);
+ if (typeof v == 'string') {
+ return v;
+ }
+ }
+ return null;
+ },
+ eval: function (text) {
+ try {
+ return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
+ text.replace(/"(\\.|[^"\\])*"/g, ''))) &&
+ eval('(' + text + ')');
+ } catch (e) {
+ return false;
+ }
+ },
+
+ parse: function (text) {
+ var at = 0;
+ var ch = ' ';
+
+ function error(m) {
+ throw {
+ name: 'JSONError',
+ message: m,
+ at: at - 1,
+ text: text
+ };
+ }
+
+ function next() {
+ ch = text.charAt(at);
+ at += 1;
+ return ch;
+ }
+
+ function white() {
+ while (ch) {
+ if (ch <= ' ') {
+ next();
+ } else if (ch == '/') {
+ switch (next()) {
+ case '/':
+ while (next() && ch != '\n' && ch != '\r') {}
+ break;
+ case '*':
+ next();
+ for (;;) {
+ if (ch) {
+ if (ch == '*') {
+ if (next() == '/') {
+ next();
+ break;
+ }
+ } else {
+ next();
+ }
+ } else {
+ error("Unterminated comment");
+ }
+ }
+ break;
+ default:
+ error("Syntax error");
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ function string() {
+ var i, s = '', t, u;
+
+ if (ch == '"') {
+ outer: while (next()) {
+ if (ch == '"') {
+ next();
+ return s;
+ } else if (ch == '\\') {
+ switch (next()) {
+ case 'b':
+ s += '\b';
+ break;
+ case 'f':
+ s += '\f';
+ break;
+ case 'n':
+ s += '\n';
+ break;
+ case 'r':
+ s += '\r';
+ break;
+ case 't':
+ s += '\t';
+ break;
+ case 'u':
+ u = 0;
+ for (i = 0; i < 4; i += 1) {
+ t = parseInt(next(), 16);
+ if (!isFinite(t)) {
+ break outer;
+ }
+ u = u * 16 + t;
+ }
+ s += String.fromCharCode(u);
+ break;
+ default:
+ s += ch;
+ }
+ } else {
+ s += ch;
+ }
+ }
+ }
+ error("Bad string");
+ }
+
+ function array() {
+ var a = [];
+
+ if (ch == '[') {
+ next();
+ white();
+ if (ch == ']') {
+ next();
+ return a;
+ }
+ while (ch) {
+ a.push(value());
+ white();
+ if (ch == ']') {
+ next();
+ return a;
+ } else if (ch != ',') {
+ break;
+ }
+ next();
+ white();
+ }
+ }
+ error("Bad array");
+ }
+
+ function object() {
+ var k, o = {};
+
+ if (ch == '{') {
+ next();
+ white();
+ if (ch == '}') {
+ next();
+ return o;
+ }
+ while (ch) {
+ k = string();
+ white();
+ if (ch != ':') {
+ break;
+ }
+ next();
+ o[k] = value();
+ white();
+ if (ch == '}') {
+ next();
+ return o;
+ } else if (ch != ',') {
+ break;
+ }
+ next();
+ white();
+ }
+ }
+ error("Bad object");
+ }
+
+ function number() {
+ var n = '', v;
+ if (ch == '-') {
+ n = '-';
+ next();
+ }
+ while (ch >= '0' && ch <= '9') {
+ n += ch;
+ next();
+ }
+ if (ch == '.') {
+ n += '.';
+ while (next() && ch >= '0' && ch <= '9') {
+ n += ch;
+ }
+ }
+ if (ch == 'e' || ch == 'E') {
+ n += 'e';
+ next();
+ if (ch == '-' || ch == '+') {
+ n += ch;
+ next();
+ }
+ while (ch >= '0' && ch <= '9') {
+ n += ch;
+ next();
+ }
+ }
+ v = +n;
+ if (!isFinite(v)) {
+ ////error("Bad number");
+ } else {
+ return v;
+ }
+ }
+
+ function word() {
+ switch (ch) {
+ case 't':
+ if (next() == 'r' && next() == 'u' && next() == 'e') {
+ next();
+ return true;
+ }
+ break;
+ case 'f':
+ if (next() == 'a' && next() == 'l' && next() == 's' &&
+ next() == 'e') {
+ next();
+ return false;
+ }
+ break;
+ case 'n':
+ if (next() == 'u' && next() == 'l' && next() == 'l') {
+ next();
+ return null;
+ }
+ break;
+ }
+ error("Syntax error");
+ }
+
+ function value() {
+ white();
+ switch (ch) {
+ case '{':
+ return object();
+ case '[':
+ return array();
+ case '"':
+ return string();
+ case '-':
+ return number();
+ default:
+ return ch >= '0' && ch <= '9' ? number() : word();
+ }
+ }
+
+ return value();
+ }
+ };
+ }();
+ }-*/;
+
private native void removeObjectPrototypeBadness(JavaScriptObject window)
/*-{
delete window.Array.prototype.toJSON;
delete window.Object.prototype.toJSON;