123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352 |
- /*
- * Copyright 2014, The gwtquery team.
- *
- * 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.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.Collections;
- 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;
-
- /**
- * Reflection handler for JsonBuilder implementation in JVM.
- */
- 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) {
- if (j == null) {
- return null;
- }
-
- 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() ? Collections.emptyList() : 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;
- }
- }
|