diff options
4 files changed, 224 insertions, 180 deletions
diff --git a/gwtquery-core/pom.xml b/gwtquery-core/pom.xml index 2664df1b..67518e26 100644 --- a/gwtquery-core/pom.xml +++ b/gwtquery-core/pom.xml @@ -30,6 +30,11 @@ <scope>provided</scope> </dependency> <dependency> + <groupId>com.google.gwt</groupId> + <artifactId>gwt-elemental</artifactId> + <version>${gwtversion}</version> + </dependency> + <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.0.0.GA</version> @@ -42,13 +47,6 @@ <classifier>sources</classifier> <scope>provided</scope> </dependency> - <!-- needed in server side if we don't include gwt-servlet - we will remove this when using elemental.json or android.json --> - <dependency> - <groupId>org.json</groupId> - <artifactId>json</artifactId> - <version>20140107</version> - </dependency> </dependencies> <build> <resources> @@ -58,6 +56,9 @@ <resource> <directory>${basedir}/src/main/super</directory> </resource> + <resource> + <directory>${project.build.directory}/generated-resources</directory> + </resource> </resources> <testResources> <testResource> @@ -100,8 +101,28 @@ <includes>**/GQueryGwtSuiteTest.java</includes> </configuration> </plugin> + <!-- We include elemental json implementation for JVM so as people + using GQuery json builders and ajax in server side don't have + to include that dependency --> + <plugin> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>unpack-dependencies</goal> + </goals> + <phase>generate-resources</phase> + <configuration> + <includeGroupIds>com.google.gwt</includeGroupIds> + <includeArtifactIds>gwt-elemental</includeArtifactIds> + <excludeTransitive>true</excludeTransitive> + <includes>elemental/json/**/*</includes> + <outputDirectory>${project.build.directory}/generated-resources</outputDirectory> + </configuration> + </execution> + </executions> + </plugin> </plugins> </build> - </project> diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index 775a789f..7bd8c792 100644 --- a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java @@ -1,5 +1,13 @@ package com.google.gwt.query.vm; +import com.google.gwt.query.client.Function; +import com.google.gwt.query.client.IsProperties; +import com.google.gwt.query.client.Properties; +import com.google.gwt.query.client.builders.JsonBuilder; +import com.google.gwt.query.client.builders.JsonFactory; +import com.google.gwt.query.client.builders.Name; +import com.google.gwt.query.rebind.JsonBuilderGenerator; + import java.lang.reflect.Array; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; @@ -10,39 +18,63 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import com.google.gwt.query.client.IsProperties; -import com.google.gwt.query.client.Function; -import com.google.gwt.query.client.Properties; -import com.google.gwt.query.client.builders.JsonBuilder; -import com.google.gwt.query.client.builders.JsonFactory; -import com.google.gwt.query.client.builders.Name; -import com.google.gwt.query.rebind.JsonBuilderGenerator; +import elemental.json.Json; +import elemental.json.JsonArray; +import elemental.json.JsonBoolean; +import elemental.json.JsonNull; +import elemental.json.JsonNumber; +import elemental.json.JsonObject; +import elemental.json.JsonString; +import elemental.json.JsonValue; +import elemental.json.impl.JreJsonNull; +/** + * Factory class to create JsonBuilders in the JVM. + * + * It uses java.util.reflect.Proxy to implement JsonBuilders + * and elemental light weight json to handle json data. + */ public class JsonFactoryJre implements JsonFactory { static JsonFactoryJre jsonFactory = new JsonFactoryJre(); + /** + * Although functions cannot be serialized to json we use JsonBuilders + * or IsProperties objects which can be used as settings in Ajax. + * Since Ajax and Promises are server side compatible, we need to handle + * Functions in JVM. + */ + static class JreJsonFunction extends JreJsonNull { + final private Function function; + public JreJsonFunction(Function f) { + function = f; + } + @Override + public String toJson() { + return function.toString(); + } + public Function getFunction() { + return function; + } + } + public static class JsonBuilderHandler implements InvocationHandler { - private JSONObject jsonObject; + private JsonObject jsonObject; public JsonBuilderHandler() { - jsonObject = new JSONObject(); + jsonObject = Json.createObject(); } - public JsonBuilderHandler(JSONObject j) { + public JsonBuilderHandler(JsonObject j) { jsonObject = j; } public JsonBuilderHandler(String payload) throws Throwable { - jsonObject = new JSONObject(payload); + jsonObject = Json.parse(payload); } @SuppressWarnings("unchecked") - private <T> Object jsonArrayToList(JSONArray j, Class<T> ctype, boolean isArray) { + private <T> Object jsonArrayToList(JsonArray j, Class<T> ctype, boolean isArray) { List<T> l = new ArrayList<T>(); for (int i = 0; j != null && i < j.length() ; i++) { l.add((T)getValue(j, i, null, null, ctype, null)); @@ -50,109 +82,110 @@ public class JsonFactoryJre implements JsonFactory { return l.isEmpty() ? null : isArray ? l.toArray((T[])Array.newInstance(ctype, l.size())) : l; } - private Object getValue(JSONArray arr, int idx, JSONObject obj, String attr, Class<?> clz, Method method) { - Object ret = null; + private Double toDouble(String attr, JsonArray arr, int idx, JsonObject obj) { try { - if (clz.isArray() || clz.equals(List.class)) { - Class<?> ctype = Object.class; - if (clz.isArray()) { - ctype = clz.getComponentType(); - } else { - Type returnType = method.getGenericReturnType(); - if (returnType instanceof ParameterizedType) { - ctype = (Class<?>)((ParameterizedType) returnType).getActualTypeArguments()[0]; - } - } - ret = jsonArrayToList(obj.getJSONArray(attr), ctype, clz.isArray()); - } else if (clz.equals(Date.class)) { - ret = new Date(obj != null ? obj.getLong(attr): arr.getLong(idx)); - } else if (clz.equals(Boolean.class) || clz.isPrimitive() && clz == Boolean.TYPE) { - try { - ret = obj != null ? obj.getBoolean(attr): arr.getBoolean(idx); - } catch (Exception e) { - return Boolean.FALSE; - } - } else if (clz.equals(Byte.class) || clz.equals(Short.class) || clz.equals(Integer.class) - || clz.isPrimitive() && (clz == Byte.TYPE || clz == Short.TYPE || clz == Integer.TYPE)) { - try { - ret = obj != null ? obj.getInt(attr): arr.getInt(idx); - } catch (Exception e) { - return 0; - } - } else if (clz.equals(Double.class) || clz.equals(Float.class) - || clz.isPrimitive() && (clz == Double.TYPE || clz == Float.TYPE)) { - try { - ret = obj != null ? obj.getDouble(attr): arr.getDouble(idx); - } catch (Exception e) { - return .0; - } - } else if (clz.equals(Long.class) - || clz.isPrimitive() && clz == Long.TYPE) { - try { - ret = obj != null ? obj.getLong(attr): arr.getLong(idx); - } catch (Exception e) { - return 0l; - } + return obj != null ? obj.getNumber(attr) : arr.getNumber(idx); + } catch (Exception e) { + return Double.valueOf(0d); + } + } + + private Object getValue(JsonArray arr, int idx, JsonObject obj, String attr, Class<?> clz, Method method) { + if (clz.equals(Boolean.class) || clz == Boolean.TYPE) { + try { + return obj != null ? obj.getBoolean(attr): arr.getBoolean(idx); + } catch (Exception e) { + return Boolean.FALSE; + } + } else if (clz.equals(Date.class)) { + return new Date((long)(obj != null ? obj.getNumber(attr): arr.getNumber(idx))); + } else if (clz.equals(Byte.class) || clz == Byte.TYPE) { + return toDouble(attr, arr, idx, obj).byteValue(); + } else if (clz.equals(Short.class) || clz == Short.TYPE) { + return toDouble(attr, arr, idx, obj).shortValue(); + } else if (clz.equals(Integer.class) || clz == Integer.TYPE) { + return toDouble(attr, arr, idx, obj).intValue(); + } else if (clz.equals(Double.class) || clz == Double.TYPE) { + return toDouble(attr, arr, idx, obj); + } else if (clz.equals(Float.class) || clz == Float.TYPE) { + return toDouble(attr, arr, idx, obj).floatValue(); + } else if (clz.equals(Long.class) || clz == Long.TYPE) { + return toDouble(attr, arr, idx, obj).longValue(); + } + + Object ret = obj != null ? obj.get(attr): arr.get(idx); + if (ret instanceof JreJsonFunction || clz.equals(Function.class)) { + return ret != null && ret instanceof JreJsonFunction ? ((JreJsonFunction)ret).getFunction() : null; + } else if (ret instanceof JsonNull) { + return null; + } else if (ret instanceof JsonString) { + return ((JsonString)ret).asString(); + } else if (ret instanceof JsonBoolean) { + return ((JsonBoolean)ret).asBoolean(); + } else if (ret instanceof JsonNumber) { + return toDouble(attr, arr, idx, obj); + } else if (ret instanceof JsonArray || clz.isArray() || clz.equals(List.class)) { + Class<?> ctype = Object.class; + if (clz.isArray()) { + ctype = clz.getComponentType(); } else { - ret = obj != null ? obj.get(attr): arr.get(idx); - if (ret == JSONObject.NULL ) { - // org.json returns an Null object instead of null when parsing. - ret = null; - } else if (clz.equals(String.class)) { - ret = String.valueOf(ret); - } else if (ret instanceof JSONObject) { - if (clz == Object.class) { - ret = jsonFactory.createBinder((JSONObject)ret); - } else if (IsProperties.class.isAssignableFrom(clz) && !clz.isAssignableFrom(ret.getClass())) { - ret = jsonFactory.create(clz, (JSONObject)ret); - } - } else if (ret instanceof Number) { - // Javascript always returns a double - ret = Double.valueOf(((Number) ret).doubleValue()); + Type returnType = method.getGenericReturnType(); + if (returnType instanceof ParameterizedType) { + ctype = (Class<?>)((ParameterizedType) returnType).getActualTypeArguments()[0]; } } - } catch (JSONException e) { + return jsonArrayToList(obj.getArray(attr), ctype, clz.isArray()); + } else if (ret instanceof JsonObject) { + if (clz == Object.class) { + return jsonFactory.createBinder((JsonObject)ret); + } else if (IsProperties.class.isAssignableFrom(clz) && !clz.isAssignableFrom(ret.getClass())) { + return jsonFactory.create(clz, (JsonObject)ret); + } } return ret; } - private <T> JSONArray listToJsonArray(Object...l) throws Throwable { - JSONArray ret = new JSONArray(); + private <T> JsonArray listToJsonArray(Object...l) throws Throwable { + JsonArray ret = Json.createArray(); for (Object o: l) { - setValue(ret, null, null, o, null); + setValue(ret, null, null, o); } return ret; } - private Object setValue(JSONArray arr, JSONObject obj, String attr, Object o, Method method) { + private Object setValue(JsonArray jsArr, JsonObject jsObj, String attr, Object val) { + if (val == null) { + return Json.createNull(); + } + try { - if (o == null) { - return o; + Class<?> valClaz = JsonValue.class; + if (val instanceof Number) { + val = ((Number)val).doubleValue(); + valClaz = Double.TYPE; + } else if (val instanceof Boolean) { + valClaz = Boolean.TYPE; + } else if (val instanceof Date) { + val = ((Date)val).getTime(); + valClaz = Double.TYPE; + } else if (val instanceof String) { + valClaz = String.class; + } else if (val instanceof IsProperties) { + val = ((IsProperties)val).getDataImpl(); + } else if (val.getClass().isArray() || val instanceof List) { + val = listToJsonArray(val.getClass().isArray() ? (Object[])val : ((List<?>)val).toArray()); + } else if (val instanceof Function) { + val = new JreJsonFunction((Function)val); } - if (o instanceof String) { - return obj != null ? obj.put(attr, o) : arr.put(o); - } else if (o instanceof Boolean) { - return obj != null ? obj.put(attr, o) : arr.put(o); - } else if (o instanceof Number) { - return obj != null ? obj.put(attr, o) : arr.put(o); - } else if (o instanceof Date) { - return obj != null ? obj.put(attr, ((Date) o).getTime()) : arr.put(((Date) o).getTime()); - } else if (o instanceof IsProperties) { - return obj != null ? obj.put(attr, ((IsProperties) o).getDataImpl()) : arr.put(((IsProperties) o).getDataImpl()); - } else if (o.getClass().isArray() || o instanceof List) { - Object[] arg; - if (o.getClass().isArray()) { - arg = (Object[])o; - } else { - arg = ((List<?>)o).toArray(); - } - JSONArray a = listToJsonArray(arg); - return obj != null ? obj.put(attr, a) : arr.put(a); + + if (jsObj != null) { + Method mth = jsObj.getClass().getMethod("put", String.class, valClaz); + mth.invoke(jsObj, new Object[]{attr, val}); + return jsObj; } else { - if (!(o instanceof Function) && !(o instanceof JSONObject)) { - System.out.println("Unkown setter object " + attr + " " + o.getClass().getName() + " " + o); - } - return obj != null ? obj.put(attr, o) : arr.put(o); + Method mth = jsArr.getClass().getMethod("set", Integer.TYPE, valClaz); + mth.invoke(jsArr, new Object[]{new Integer(jsArr.length()), val}); + return jsArr; } } catch (Throwable e) { e.printStackTrace(); @@ -170,8 +203,9 @@ public class JsonFactoryJre implements JsonFactory { String attr = name != null ? name.value() : deCapitalize(mname.replaceFirst("^[gs]et", "")); if ("getFieldNames".equals(mname)) { - return JSONObject.getNames(jsonObject); + return jsonObject.keys(); } else if ("as".equals(mname)) { + @SuppressWarnings("unchecked") Class<? extends JsonBuilder> clz = (Class<? extends JsonBuilder>)args[0]; return jsonFactory.create(clz, jsonObject); } else if ("getJsonName".equals(mname)) { @@ -180,10 +214,10 @@ public class JsonFactoryJre implements JsonFactory { return jsonObject; } else if (largs > 0 && ("parse".equals(mname) || "load".equals(mname))) { String json = String.valueOf(args[0]); - if (largs > 1 && Boolean.TRUE.equals(args[0])) { + if (largs > 1 && Boolean.TRUE.equals(args[1])) { json = Properties.wrapPropertiesString(json); } - jsonObject = new JSONObject(json); + jsonObject = Json.parse(json); } else if (mname.matches("toString")) { return jsonObject.toString(); } else if (mname.matches("toJsonWithName")) { @@ -201,15 +235,15 @@ public class JsonFactoryJre implements JsonFactory { Class<?> ret = method.getReturnType(); return getValue(null, 0, jsonObject, attr, ret, method); } else if (largs == 2 && mname.equals("set")) { - setValue(null, jsonObject, String.valueOf(args[0]), args[1], method); + setValue(null, jsonObject, String.valueOf(args[0]), args[1]); return proxy; } else if (largs == 1 || mname.startsWith("set")) { - setValue(null, jsonObject, attr, args[0], method); + setValue(null, jsonObject, attr, args[0]); return proxy; } return null; } - + private String deCapitalize(String s) { return s != null && s.length() > 0 ? s.substring(0, 1).toLowerCase() + s.substring(1) : s; } @@ -224,50 +258,21 @@ public class JsonFactoryJre implements JsonFactory { } return null; } - - private String param(JSONObject o) { + + private String param(JsonObject o) { String ret = ""; - for (String k : JSONObject.getNames(o)) { + for (String k : o.keys()) { ret += ret.isEmpty() ? "" : "&"; - JSONObject p = null; - JSONArray a = null; - String s = null; - try { - a = o.getJSONArray(k); - } catch (Exception e) { - } - if (a != null) { - for (int i = 0, l = a.length(); i < l ; i++) { + JsonValue v = o.get(k); + if (v instanceof JsonArray) { + for (int i = 0, l = ((JsonArray)v).length(); i < l ; i++) { ret += i > 0 ? "&" : ""; - try { - p = a.getJSONObject(i); - } catch (Exception e) { - try { - s = String.valueOf(a.get(i)); - } catch (Exception d) { - } - } - if (p != null) { - ret += k + "[]=" + p.toString(); - } else if (s != null){ - ret += k + "[]=" + s; - } + JsonValue e = ((JsonArray)v).get(i); + ret += k + "[]=" + e.toJson(); } } else { - try { - p = o.getJSONObject(k); - } catch (Exception e) { - try { - s = String.valueOf(o.get(k)); - } catch (Exception d) { - } - } - if (p != null) { - ret += k + "=" + p.toString(); - } else if (s != null) { - if (!"null".equalsIgnoreCase(s)) { - ret += k + "=" + s; - } + if (v != null && !(v instanceof JsonNull)) { + ret += k + "=" + v.toJson(); } } } @@ -276,7 +281,7 @@ public class JsonFactoryJre implements JsonFactory { } @SuppressWarnings("unchecked") - public <T> T create(Class<T> clz, JSONObject jso) { + public <T> T create(Class<T> clz, JsonObject jso) { InvocationHandler handler = new JsonBuilderHandler(jso); return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] {clz}, handler); } @@ -286,13 +291,13 @@ public class JsonFactoryJre implements JsonFactory { InvocationHandler handler = new JsonBuilderHandler(); return (T) Proxy.newProxyInstance(clz.getClassLoader(), new Class[] {clz}, handler); } - + public IsProperties createBinder() { InvocationHandler handler = new JsonBuilderHandler(); return (IsProperties)Proxy.newProxyInstance(IsProperties.class.getClassLoader(), new Class[] {IsProperties.class}, handler); } - - public IsProperties createBinder(JSONObject jso) { + + public IsProperties createBinder(JsonObject jso) { InvocationHandler handler = new JsonBuilderHandler(jso); return (IsProperties)Proxy.newProxyInstance(IsProperties.class.getClassLoader(), new Class[] {IsProperties.class}, handler); } diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestJre.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestJre.java index 1167651d..cf98d8b9 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestJre.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/ajax/AjaxTestJre.java @@ -15,11 +15,9 @@ */ package com.google.gwt.query.client.ajax; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - -import javax.servlet.Servlet; +import com.google.gwt.core.shared.GWT; +import com.google.gwt.query.servlet.GQAjaxTestServlet; +import com.google.gwt.query.vm.AjaxTransportJre; import org.mortbay.jetty.Server; import org.mortbay.jetty.handler.HandlerWrapper; @@ -27,32 +25,41 @@ import org.mortbay.jetty.servlet.DefaultServlet; import org.mortbay.jetty.webapp.WebAppClassLoader; import org.mortbay.jetty.webapp.WebAppContext; -import com.google.gwt.query.servlet.GQAjaxTestServlet; -import com.google.gwt.query.vm.AjaxTransportJre; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; + +import javax.servlet.Servlet; /** * Tests for Data Binders and Ajax run in the JVM */ public class AjaxTestJre extends AjaxTests { - + static Server server; static int port = new Random().nextInt(1000) + 2000; public String getModuleName() { return null; } - + public AjaxTestJre() throws Exception { + // Disable stderr, so as stack traces of expected failures do not + // mess the output. + System.setErr(new PrintStream(new ByteArrayOutputStream())); + String localDomain = "http://127.0.0.1:" + port; AjaxTransportJre.enableCORS(localDomain); String corsDomain = "http://localhost:" + port; - + echoUrl = localDomain + "/" + servletPath; echoUrlCORS = corsDomain + "/" + servletPath + "?cors=true"; startWebServer(port); } - + protected void startWebServer(int port) throws Exception { if (server == null) { final Map<String, Class<? extends Servlet>> servlets = new HashMap<String, Class<? extends Servlet>>(); @@ -63,7 +70,7 @@ public class AjaxTestJre extends AjaxTests { public static Server createWebServer(final int port, final String resourceBase, final String[] classpath, final Map<String, Class<? extends Servlet>> servlets, final HandlerWrapper handler) throws Exception { - + final Server server = new Server(port); final WebAppContext context = new WebAppContext(); diff --git a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java index 965bf161..7158fe8d 100644 --- a/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java +++ b/gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java @@ -15,10 +15,7 @@ */ package com.google.gwt.query.client.dbinding; -import java.util.Arrays; -import java.util.Date; -import java.util.List; - +import com.google.gwt.core.shared.GWT; import com.google.gwt.junit.client.GWTTestCase; import com.google.gwt.query.client.Function; import com.google.gwt.query.client.GQ; @@ -26,6 +23,12 @@ import com.google.gwt.query.client.IsProperties; import com.google.gwt.query.client.builders.JsonBuilder; import com.google.gwt.query.client.builders.Name; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + /** * Tests for Deferred which can run either in JVM and GWT */ @@ -41,11 +44,13 @@ public class DataBindingTestJre extends GWTTestCase { p1.set("b", 1); p1.set("c", "null"); p1.set("d", null); + p1.set("e", true); assertEquals("1", p1.get("a")); assertEquals(Double.valueOf(1), p1.get("b")); assertEquals("null", p1.get("c")); assertNull(p1.get("d")); + assertTrue((Boolean)p1.get("e")); p1 = GQ.create(p1.toJson()); @@ -57,7 +62,7 @@ public class DataBindingTestJre extends GWTTestCase { public interface Item extends JsonBuilder { public static enum Type {BIG, SMALL} - + Date getDate(); void setDate(Date d); Type getType(); @@ -79,6 +84,8 @@ public class DataBindingTestJre extends GWTTestCase { JsonExample setD(long l); List<Item> getItems(); void setItems(List<Item> a); + Item getI(); + void setI(Item i); String y(); void y(String s); Function getF(); @@ -124,21 +131,25 @@ public class DataBindingTestJre extends GWTTestCase { assertTrue(functionRun); Item i1 = GQ.create(Item.class); - Item i2 = GQ.create(Item.class); i1.setDate(new Date(2000)); + c.setI(i1); + assertEquals(2000l, c.getI().getDate().getTime()); + + Item i2 = GQ.create(Item.class); i2.setDate(new Date(3000)); Item[] items = new Item[]{i1, i2}; c.setItems(Arrays.asList(items)); assertEquals(2000l, c.getItems().get(0).getDate().getTime()); assertEquals(3000l, c.getItems().get(1).getDate().getTime()); + assertFalse(c.toJson().startsWith("{\"jsonExample\":")); assertTrue(c.toJsonWithName().startsWith("{\"jsonExample\":")); assertTrue(c.toJson().contains("\"items\":[{\"date\":")); - assertTrue(c.toQueryString().contains("t[]=bar")); + assertTrue(c.toQueryString().replace("\"bar\"", "bar").contains("t[]=bar")); assertTrue(c.toQueryString().contains("a=1")); assertTrue(c.toQueryString().contains("\"a\":2")); - + assertEquals(1, c.<Number>get("a").intValue()); } }
\ No newline at end of file |