aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManuel Carrasco Moñino <manolo@apache.org>2014-12-26 16:58:26 +0100
committerManuel Carrasco Moñino <manolo@apache.org>2014-12-26 16:58:26 +0100
commitca8329caa010b70f3c610b85226c16c65cda2d57 (patch)
tree30c2b5dce0342fc37ace40c31e03a6605ab1f412
parent45138b470ae618dbe986dc75bdbadae6ffbe991f (diff)
parentb571d28f9371a4c95837ddf383699d7211572857 (diff)
downloadgwtquery-ca8329caa010b70f3c610b85226c16c65cda2d57.tar.gz
gwtquery-ca8329caa010b70f3c610b85226c16c65cda2d57.zip
Merge pull request #325 from apanizo/master
Parsing only methods specified in JsonBuilder interface from a given json
-rw-r--r--gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java9
-rw-r--r--gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java15
-rw-r--r--gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java36
-rw-r--r--gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java2
-rw-r--r--gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonBuilderHandler.java328
-rw-r--r--gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java241
-rw-r--r--gwtquery-core/src/test/java/com/google/gwt/query/client/dbinding/DataBindingTestJre.java61
7 files changed, 437 insertions, 255 deletions
diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java
index bcd79cdb..f630cf21 100644
--- a/gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java
+++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/IsProperties.java
@@ -31,6 +31,14 @@ public interface IsProperties {
* parses a json string and loads the resulting properties object.
*/
<T extends IsProperties> T parse(String json);
+
+ /**
+ * Removes the extra JSON and leaves only the setters/getters described
+ * in the JsonBuilder interface.
+ * If the object contains another IsProperties attributes the method strip()
+ * is called on them.
+ */
+ <T extends IsProperties> T strip();
/**
* Returns the underlying object, normally a Properties jso in client
@@ -77,7 +85,6 @@ public interface IsProperties {
*/
String getJsonName();
-
/**
* converts a JsonBuilder instance into another JsonBuilder type but
* preserving the underlying data object.
diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java
index db35f5d6..2c2ba54c 100644
--- a/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java
+++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java
@@ -142,7 +142,7 @@ public class Properties extends JavaScriptObject implements IsProperties {
public final Object getObject(Object name) {
return c().get(String.valueOf(name));
}
-
+
public final Properties getProperties(Object name) {
return getJavaScriptObject(name);
}
@@ -176,9 +176,9 @@ public class Properties extends JavaScriptObject implements IsProperties {
/**
* Adds a new native js function to the properties object.
* This native function will wrap the passed java Function.
- *
+ *
* Its useful for exporting or importing to javascript.
- *
+ *
*/
public final native <T> void setFunction(T name, Function f) /*-{
if (!f) return;
@@ -218,6 +218,11 @@ public class Properties extends JavaScriptObject implements IsProperties {
}
return getDataImpl();
}
+
+ @SuppressWarnings("unchecked")
+ public final <J extends IsProperties> J strip() {
+ return (J)this;
+ }
public final <J extends IsProperties> J parse(String json) {
return load(JsUtils.parseJSON(json));
@@ -230,11 +235,11 @@ public class Properties extends JavaScriptObject implements IsProperties {
public final String toJson() {
return toJsonString();
}
-
+
public final String toJsonWithName() {
return toJsonWithName(getJsonName());
}
-
+
public final String toJsonWithName(String name) {
return "{\"" + name + "\":{" + toJson() + "}";
}
diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java
index c09836a5..57f5a909 100644
--- a/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java
+++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java
@@ -19,12 +19,18 @@ import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.JsArray;
import com.google.gwt.query.client.IsProperties;
import com.google.gwt.query.client.Properties;
+import com.google.gwt.query.client.js.JsCache;
import com.google.gwt.query.client.js.JsObjectArray;
import com.google.gwt.query.client.js.JsUtils;
+import com.google.gwt.user.client.Window;
+
+import java.util.Arrays;
+import java.util.List;
public abstract class JsonBuilderBase<J extends JsonBuilderBase<?>> implements JsonBuilder {
protected Properties p = Properties.create();
+ protected String[] fieldNames = new String[] {};
@SuppressWarnings("unchecked")
@Override
@@ -40,6 +46,20 @@ public abstract class JsonBuilderBase<J extends JsonBuilderBase<?>> implements J
@SuppressWarnings("unchecked")
@Override
+ public J strip() {
+ List<String> names = Arrays.asList(getFieldNames());
+ for (String jsonName : p.getFieldNames()) {
+ // TODO: figure out a way so as we can generate some marks in generated class in
+ // order to call getters to return JsonBuilder object given an an attribute name
+ if (!names.contains(jsonName)) {
+ p.<JsCache>cast().delete(jsonName);
+ }
+ }
+ return (J)this;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
public J load(Object prp) {
assert prp == null || prp instanceof JavaScriptObject || prp instanceof String;
if (prp != null && prp instanceof String) {
@@ -98,7 +118,7 @@ public abstract class JsonBuilderBase<J extends JsonBuilderBase<?>> implements J
public String toJson() {
return p.tostring();
}
-
+
public String toJsonWithName() {
return "{\"" + getJsonName() + "\":" + p.tostring() + "}";
}
@@ -108,22 +128,22 @@ public abstract class JsonBuilderBase<J extends JsonBuilderBase<?>> implements J
public Properties getProperties() {
return p;
}
-
+
@Override
public String toQueryString() {
return p.toQueryString();
}
-
+
@SuppressWarnings("unchecked")
@Override
public Properties getDataImpl() {
return p;
}
-
+
public <T> T get(Object key) {
return p.get(key);
}
-
+
@SuppressWarnings("unchecked")
public <T extends IsProperties> T set(Object key, Object val) {
if (val instanceof IsProperties) {
@@ -133,8 +153,12 @@ public abstract class JsonBuilderBase<J extends JsonBuilderBase<?>> implements J
}
return (T)this;
}
-
+
public <T extends JsonBuilder> T as(Class<T> clz) {
return p.as(clz);
}
+
+ public final String[] getFieldNames() {
+ return fieldNames;
+ }
}
diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java
index c2383c19..197e23b8 100644
--- a/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java
+++ b/gwtquery-core/src/main/java/com/google/gwt/query/rebind/JsonBuilderGenerator.java
@@ -143,7 +143,7 @@ public class JsonBuilderGenerator extends Generator {
for (Iterator<String> it = attrs.iterator(); it.hasNext();) {
ret += (ret.isEmpty() ? "" : ",") + "\"" + it.next() + "\"";
}
- sw.println("public final String[] getFieldNames() {return new String[]{" + ret + "};}");
+ sw.println("{ fieldNames = new String[]{" + ret + "}; }");
}
public void generateMethod(SourceWriter sw, JMethod method, String name, TreeLogger logger)
diff --git a/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonBuilderHandler.java b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonBuilderHandler.java
new file mode 100644
index 00000000..8d9b9a4c
--- /dev/null
+++ b/gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonBuilderHandler.java
@@ -0,0 +1,328 @@
+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.Name;
+import com.google.gwt.query.rebind.JsonBuilderGenerator;
+import com.google.gwt.query.vm.JsonFactoryJre.JreJsonFunction;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+
+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;
+
+public class JsonBuilderHandler implements InvocationHandler {
+
+ static JsonFactoryJre jsonFactory = new JsonFactoryJre();
+
+ private JsonObject jsonObject;
+
+ public JsonBuilderHandler() {
+ jsonObject = Json.createObject();
+ }
+
+ public JsonBuilderHandler(JsonObject j) {
+ jsonObject = j;
+ }
+
+ public JsonBuilderHandler(String payload) throws Throwable {
+ jsonObject = Json.parse(payload);
+ }
+
+ @SuppressWarnings("unchecked")
+ 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));
+ }
+ return l.isEmpty() ? null : isArray ? l.toArray((T[]) Array.newInstance(ctype, l.size())) : l;
+ }
+
+ private Double toDouble(String attr, JsonArray arr, int idx, JsonObject obj) {
+ try {
+ 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 {
+ Type returnType = method.getGenericReturnType();
+ if (returnType instanceof ParameterizedType) {
+ ctype = (Class<?>) ((ParameterizedType) returnType).getActualTypeArguments()[0];
+ }
+ }
+ 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 = Json.createArray();
+ for (Object o : l) {
+ setValue(ret, null, null, o);
+ }
+ return ret;
+ }
+
+ private Object setValue(JsonArray jsArr, JsonObject jsObj, String attr, Object val) {
+ if (val == null) {
+ return Json.createNull();
+ }
+
+ try {
+ 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 (jsObj != null) {
+ Method mth = jsObj.getClass().getMethod("put", String.class, valClaz);
+ mth.invoke(jsObj, new Object[] {attr, val});
+ return jsObj;
+ } else {
+ 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();
+ }
+ return null;
+ }
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ String mname = method.getName();
+ Class<?>[] classes = method.getParameterTypes();
+ int largs = classes.length;
+
+ Name name = method.getAnnotation(Name.class);
+ String attr = name != null ? name.value() : methodName2AttrName(mname);
+
+ if ("getFieldNames".equals(mname)) {
+ 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)) {
+ return JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass()));
+ } else if (mname.matches("getProperties|getDataImpl")) {
+ 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[1])) {
+ json = Properties.wrapPropertiesString(json);
+ }
+ jsonObject = Json.parse(json);
+ } else if ("strip".equals(mname)) {
+ stripProxy((JsonBuilder) proxy);
+ } else if (mname.matches("toString")) {
+ return jsonObject.toString();
+ } else if (mname.matches("toJsonWithName")) {
+ String jsonName =
+ JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass()));
+ return "{\"" + jsonName + "\":" + jsonObject.toString() + "}";
+ } else if (mname.matches("toJson")) {
+ return jsonObject.toString();
+ } else if ("toQueryString".equals(mname)) {
+ return param(jsonObject);
+ } else if (largs == 1 && mname.equals("get")) {
+ Class<?> ret = method.getReturnType();
+ attr = String.valueOf(args[0]);
+ return getValue(null, 0, jsonObject, attr, ret, method);
+ } else if (largs == 0 || mname.startsWith("get")) {
+ 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]);
+ return proxy;
+ } else if (largs == 1 || mname.startsWith("set")) {
+ setValue(null, jsonObject, attr, args[0]);
+ return proxy;
+ }
+ return null;
+ }
+
+ public String methodName2AttrName(String s) {
+ return deCapitalize(s.replaceFirst("^[gs]et", ""));
+ }
+
+ private String deCapitalize(String s) {
+ return s != null && s.length() > 0 ? s.substring(0, 1).toLowerCase() + s.substring(1) : s;
+ }
+
+ /*
+ * This method removes all the json which is not mapped into a
+ * method inside the JsonBuilder Object.
+ * Also if the proxy contains another JsonBuilder in their methods
+ * the method strip() is called.
+ */
+ private void stripProxy(JsonBuilder proxy) throws Throwable {
+ Class<?> type = proxy.getClass().getInterfaces()[0];
+
+ HashSet<String> validAttrs = getAttributeNames(type.getMethods());
+ Hashtable<String, Method> ispropertyGetters = getJsonBuilders(type.getMethods());
+
+ for (String key : jsonObject.keys()) {
+ String name = methodName2AttrName(key);
+ if (!validAttrs.contains(name)) {
+ jsonObject.remove(key);
+ continue;
+ }
+ Method ispropertyGetter = ispropertyGetters.get(name);
+ if (ispropertyGetter != null) {
+ ((IsProperties) invoke(proxy, ispropertyGetter, new Object[] {})).strip();
+ }
+ }
+ }
+
+ private String getDataBindingClassName(Class<?> type) {
+ for (Class<?> c : type.getInterfaces()) {
+ if (c.equals(JsonBuilder.class)) {
+ return type.getName();
+ } else {
+ return getDataBindingClassName(c);
+ }
+ }
+ return null;
+ }
+
+ private String param(JsonObject o) {
+ String ret = "";
+ for (String k : o.keys()) {
+ ret += ret.isEmpty() ? "" : "&";
+ JsonValue v = o.get(k);
+ if (v instanceof JsonArray) {
+ for (int i = 0, l = ((JsonArray) v).length(); i < l; i++) {
+ ret += i > 0 ? "&" : "";
+ JsonValue e = ((JsonArray) v).get(i);
+ ret += k + "[]=" + e.toJson();
+ }
+ } else {
+ if (v != null && !(v instanceof JsonNull)) {
+ ret += k + "=" + v.toJson();
+ }
+ }
+ }
+ return ret;
+ }
+
+ private HashSet<String> getAttributeNames(Method[] methods) {
+ HashSet<String> valid = new HashSet<String>();
+
+ if (methods == null || methods.length == 0) {
+ return valid;
+ }
+
+ for (Method m : methods) {
+ String attr = methodName2AttrName(m.getName());
+ Name annotation = m.getAnnotation(Name.class);
+
+ if (annotation != null) {
+ attr = annotation.value();
+ }
+ valid.add(attr);
+ }
+ return valid;
+ }
+
+ private Hashtable<String, Method> getJsonBuilders(Method[] methods) {
+ Hashtable<String, Method> ispropertyGetters = new Hashtable<String, Method>();
+
+ if (methods == null || methods.length == 0) {
+ return ispropertyGetters;
+ }
+
+ for (Method m : methods) {
+ Class<?>[] classes = m.getParameterTypes();
+ boolean isJsonBuilder =
+ classes.length == 0 && IsProperties.class.isAssignableFrom(m.getReturnType());
+ if (isJsonBuilder) {
+ String attr = methodName2AttrName(m.getName());
+ ispropertyGetters.put(attr, m);
+ }
+ }
+
+ return ispropertyGetters;
+ }
+} \ No newline at end of file
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 7bd8c792..54e8aab3 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
@@ -2,30 +2,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;
-import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
-import java.lang.reflect.Type;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-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;
/**
@@ -36,7 +19,7 @@ import elemental.json.impl.JreJsonNull;
*/
public class JsonFactoryJre implements JsonFactory {
- static JsonFactoryJre jsonFactory = new JsonFactoryJre();
+
/**
* Although functions cannot be serialized to json we use JsonBuilders
@@ -58,228 +41,6 @@ public class JsonFactoryJre implements JsonFactory {
}
}
- public static class JsonBuilderHandler implements InvocationHandler {
- private JsonObject jsonObject;
-
- public JsonBuilderHandler() {
- jsonObject = Json.createObject();
- }
-
- public JsonBuilderHandler(JsonObject j) {
- jsonObject = j;
- }
-
- public JsonBuilderHandler(String payload) throws Throwable {
- jsonObject = Json.parse(payload);
- }
-
- @SuppressWarnings("unchecked")
- 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));
- }
- return l.isEmpty() ? null : isArray ? l.toArray((T[])Array.newInstance(ctype, l.size())) : l;
- }
-
- private Double toDouble(String attr, JsonArray arr, int idx, JsonObject obj) {
- try {
- 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 {
- Type returnType = method.getGenericReturnType();
- if (returnType instanceof ParameterizedType) {
- ctype = (Class<?>)((ParameterizedType) returnType).getActualTypeArguments()[0];
- }
- }
- 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 = Json.createArray();
- for (Object o: l) {
- setValue(ret, null, null, o);
- }
- return ret;
- }
-
- private Object setValue(JsonArray jsArr, JsonObject jsObj, String attr, Object val) {
- if (val == null) {
- return Json.createNull();
- }
-
- try {
- 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 (jsObj != null) {
- Method mth = jsObj.getClass().getMethod("put", String.class, valClaz);
- mth.invoke(jsObj, new Object[]{attr, val});
- return jsObj;
- } else {
- 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();
- }
- return null;
- }
-
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- String mname = method.getName();
- Class<?>[] classes = method.getParameterTypes();
- int largs = classes.length;
-
- Name name = method.getAnnotation(Name.class);
- String attr = name != null ? name.value() : deCapitalize(mname.replaceFirst("^[gs]et", ""));
-
- if ("getFieldNames".equals(mname)) {
- 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)) {
- return JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass()));
- } else if (mname.matches("getProperties|getDataImpl")) {
- 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[1])) {
- json = Properties.wrapPropertiesString(json);
- }
- jsonObject = Json.parse(json);
- } else if (mname.matches("toString")) {
- return jsonObject.toString();
- } else if (mname.matches("toJsonWithName")) {
- String jsonName = JsonBuilderGenerator.classNameToJsonName(getDataBindingClassName(proxy.getClass()));
- return "{\"" + jsonName + "\":"+ jsonObject.toString() + "}";
- } else if (mname.matches("toJson")) {
- return jsonObject.toString() ;
- } else if ("toQueryString".equals(mname)) {
- return param(jsonObject);
- } else if (largs == 1 && mname.equals("get")) {
- Class<?> ret = method.getReturnType();
- attr = String.valueOf(args[0]);
- return getValue(null, 0, jsonObject, attr, ret, method);
- } else if (largs == 0 || mname.startsWith("get")) {
- 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]);
- return proxy;
- } else if (largs == 1 || mname.startsWith("set")) {
- 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;
- }
-
- private String getDataBindingClassName(Class<?> type) {
- for (Class<?> c : type.getInterfaces()) {
- if (c.equals(JsonBuilder.class)) {
- return type.getName();
- } else {
- return getDataBindingClassName(c);
- }
- }
- return null;
- }
-
- private String param(JsonObject o) {
- String ret = "";
- for (String k : o.keys()) {
- ret += ret.isEmpty() ? "" : "&";
- JsonValue v = o.get(k);
- if (v instanceof JsonArray) {
- for (int i = 0, l = ((JsonArray)v).length(); i < l ; i++) {
- ret += i > 0 ? "&" : "";
- JsonValue e = ((JsonArray)v).get(i);
- ret += k + "[]=" + e.toJson();
- }
- } else {
- if (v != null && !(v instanceof JsonNull)) {
- ret += k + "=" + v.toJson();
- }
- }
- }
- return ret;
- }
- }
-
@SuppressWarnings("unchecked")
public <T> T create(Class<T> clz, JsonObject jso) {
InvocationHandler handler = new JsonBuilderHandler(jso);
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 7158fe8d..5ea76a18 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
@@ -23,12 +23,11 @@ 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
*/
@@ -152,4 +151,62 @@ public class DataBindingTestJre extends GWTTestCase {
assertEquals(1, c.<Number>get("a").intValue());
}
+
+ public interface GAddress extends JsonBuilder {
+ String street();
+ String city();
+ }
+
+ public interface GUser extends JsonBuilder {
+ @Name("_id")
+ String getId();
+
+ int getAge();
+ String getName();
+ GAddress address();
+ }
+
+ public static final String JSON_USER_EXAMPLE = " { "
+ + " '_id': 'aaabbbccc', "
+ + " 'email': 'foo@bar.com', "
+ + " 'age': 27, "
+ + " 'name': 'Foo Bar', "
+ + " 'address': {"
+ + " 'street': 'Street Foo N6', "
+ + " 'phone': '670'"
+ + " }"
+ + "}";
+
+ public void
+ test_parse_json() {
+ GUser entity = GQ.create(GUser.class);
+ entity.parse(JSON_USER_EXAMPLE, true);
+
+ assertNotNull(entity.get("email"));
+ assertEquals("aaabbbccc", entity.getId());
+ assertEquals(27, entity.getAge());
+ assertEquals("Foo Bar", entity.getName());
+ assertNotNull(entity.address());
+ assertEquals("Street Foo N6", entity.address().street());
+ assertNotNull(entity.address().get("phone"));
+ }
+
+ public void
+ test_parse_strict_json() {
+ GUser entity = GQ.create(GUser.class);
+ entity.parse(JSON_USER_EXAMPLE, true);
+ entity.strip();
+
+ assertEquals("aaabbbccc", entity.getId());
+ assertNull(entity.get("email"));
+ assertEquals(27, entity.getAge());
+ assertEquals("Foo Bar", entity.getName());
+ assertNotNull(entity.address());
+ assertEquals("Street Foo N6", entity.address().street());
+
+ // Recursion not implemented in client side
+ if (GWT.isScript()) {
+ assertNull(entity.address().get("phone"));
+ }
+ }
} \ No newline at end of file