From: Manolo Carrasco Date: Fri, 2 Jan 2015 13:26:04 +0000 (+0100) Subject: Merge branch 'mcm_styling' into mcm_special_events X-Git-Tag: gwtquery-project-1.4.3~4^2~2 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=083aeae611e94e9121e715b2d5e4d2584abe4f6a;p=gwtquery.git Merge branch 'mcm_styling' into mcm_special_events Conflicts: gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Events.java gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/LazyEvents.java gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/EventsListener.java gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java --- 083aeae611e94e9121e715b2d5e4d2584abe4f6a diff --cc gwtquery-core/src/main/java/com/google/gwt/query/client/Properties.java index 0997404e,c9414232..c75dd238 --- 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 @@@ -218,6 -218,11 +218,11 @@@ public class Properties extends JavaScr } return getDataImpl(); } + + @SuppressWarnings("unchecked") + public final J strip() { - return (J)this; ++ return (J) this; + } public final J parse(String json) { return load(JsUtils.parseJSON(json)); diff --cc gwtquery-core/src/main/java/com/google/gwt/query/client/builders/JsonBuilderBase.java index 4c25117a,a33f676b..f0c46931 --- 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,9 -19,19 +19,18 @@@ import com.google.gwt.core.client.JavaS 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; + + /** + * Common class for all JsonBuilder implementations. + * + * @param + */ public abstract class JsonBuilderBase> implements JsonBuilder { protected Properties p = Properties.create(); @@@ -38,6 -49,20 +48,20 @@@ return fix ? parse(Properties.wrapPropertiesString(json)) : parse(json); } + @SuppressWarnings("unchecked") + @Override + public J strip() { + List 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.cast().delete(jsonName); + } + } - return (J)this; ++ return (J) this; + } + @SuppressWarnings("unchecked") @Override public J load(Object prp) { diff --cc gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImpl.java index 4bd133ec,d7b83337..0a466a07 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImpl.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/impl/DocumentStyleImpl.java @@@ -208,7 -212,7 +212,7 @@@ public class DocumentStyleImpl } /** -- * Return whether the element is visible ++ * Return whether the element is visible. */ public boolean isVisible(Element e) { return SelectorEngine.filters.get("visible").f(e, 0); diff --cc gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java index dff21481,c3b0c5ce..13f6c4a3 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/js/JsCache.java @@@ -231,7 -236,7 +236,7 @@@ public class JsCache extends JavaScript checkNull(this); } -- private final native JsArrayString keysImpl() /*-{ ++ private native JsArrayString keysImpl() /*-{ var key, keys=[]; // Chrome in DevMode sets '__gwt_ObjectId' to JS objects // GWT sets '$H' when calling getHashCode (see com/google/gwt/core/client/impl/Impl.java) diff --cc gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Events.java index a35ebb70,84ce65dd..3983791a --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Events.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/Events.java @@@ -134,9 -135,8 +134,8 @@@ public class Events extends GQuery public GQuery live(int eventbits, String nameSpace, final Object data, Function... funcs) { EventsListener.getInstance(Element.is(currentContext) ? (Element) currentContext : body).live( - eventbits, nameSpace, null, null, currentSelector, data, funcs); + eventbits, nameSpace, null, currentSelector, data, funcs); return this; - } public GQuery live(String eventName, final Object data, Function... funcs) { @@@ -294,29 -281,35 +292,29 @@@ * Trigger a html event in all matched elements. * * @param htmlEvent An string representing the desired html event. - * @functions a set of function to run if the event is not canceled. + * @param datas a set of object passed as data when executed the handlers + * @param functions a set of function to run. */ public Events triggerHtmlEvent(String htmlEvent, Object[] datas, final Function... functions) { - SpecialEvent specialEvent = EventsListener.special.get(htmlEvent); - boolean isSpecialEvent = specialEvent != null; - - String originalEventName = htmlEvent; - String delegateEventName = isSpecialEvent ? specialEvent.getDelegateType() : htmlEvent; - - NativeEvent e = document.createHtmlEvent(delegateEventName, true, true); - - if (isSpecialEvent) { - GqEvent.setOriginalEventType(e, originalEventName); - } - - if ("submit".equals(htmlEvent)) { - Function submitFunction = new Function() { - public void f(Element e) { - // first submit the form then call the others functions - if (FormElement.is(e)) { - e. cast().submit(); + for (EventName part : EventName.split(htmlEvent)) { + NativeEvent e = document.createHtmlEvent(part.eventName, true, true); + JsUtils.prop(e, "namespace", part.nameSpace); - if ("submit".equals(part.eventName)){ ++ if ("submit".equals(part.eventName)) { + Function submitFunction = new Function() { + public void f(Element e) { + // first submit the form then call the others functions + if (FormElement.is(e)) { + e.cast().submit(); + } + callHandlers(e, getEvent(), functions); } - callHandlers(e, getEvent(), functions); - } - }; - dispatchEvent(e, datas, submitFunction); - } else { - dispatchEvent(e, datas, functions); + }; + dispatchEvent(e, datas, submitFunction); + } else { + dispatchEvent(e, datas, functions); + } } + return this; } diff --cc gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java index 693990d5,fed2ffdf..cefedceb --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/Transitions.java @@@ -268,7 -268,7 +268,7 @@@ public class Transitions extends GQuer t.setFromString(prop, value); getStyleImpl().setStyleProperty(e, transform, t.toString()); } -- } else if (!invalidTransitionNamesRegex.test(prop)){ ++ } else if (!invalidTransitionNamesRegex.test(prop)) { super.css(prop, value); } return this; @@@ -297,7 -297,7 +297,7 @@@ private Transform getTransform(Element e, String initial) { Transform t = data(e, TRANSFORM); -- if (t == null || initial != null && !initial.isEmpty() ) { ++ if (t == null || initial != null && !initial.isEmpty()) { t = new Transform(initial); data(e, TRANSFORM, t); } @@@ -334,12 -334,12 +334,12 @@@ final double queuedAt = delay > 0 ? Duration.currentTimeMillis() : 0; // Use gQuery queue, so as we can chain transitions, animations etc. -- queue(new Function(){ ++ queue(new Function() { public void f() { // This is called once per element final String oldTransitionValue = $(this).css(transition); // Recompute delay based on the time spent in the queue -- int d = Math.max(0, delay - (int)(Duration.currentTimeMillis() - queuedAt)); ++ int d = Math.max(0, delay - (int) (Duration.currentTimeMillis() - queuedAt)); // Generate transition value String attribs = duration + "ms" + " " + ease + " " + d + "ms"; String newTransitionValue = ""; diff --cc gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/TransitionsAnimation.java index a671d92e,6155540a..4636b12e --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/TransitionsAnimation.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/effects/TransitionsAnimation.java @@@ -82,8 -85,8 +85,8 @@@ public class TransitionsAnimation exten int bit = currentAction == Action.HIDE ? 1 : 0; String originX = "left", originY = "top"; -- int scaleXini = 0^bit, scaleYini = scaleXini; -- int scaleXend = 1^bit, scaleYend = scaleXend; ++ int scaleXini = 0 ^ bit, scaleYini = scaleXini; ++ int scaleXend = 1 ^ bit, scaleYend = scaleXend; if (direction == Direction.VERTICAL) { scaleXini = scaleXend = 1; @@@ -171,7 -174,7 +174,7 @@@ trsStart = "" + st; double en = Double.parseDouble(trsEnd); -- trsEnd = "" + (st + n*en); ++ trsEnd = "" + (st + n * en); } // Deal with non px units like "%" @@@ -208,7 -210,7 +210,7 @@@ private Properties getFxProperties(boolean isStart) { Properties p = $$(); for (int i = 0; i < effects.length(); i++) { -- TransitFx fx = (TransitFx)effects.get(i); ++ TransitFx fx = (TransitFx) effects.get(i); String val = isStart ? fx.transitStart : fx.transitEnd; if (!val.isEmpty()) { p.set(fx.cssprop, val + fx.unit); @@@ -238,8 -240,8 +240,10 @@@ // Compute final properties p = getFxProperties(false); -- g.transition(p, duration, easing, delay, new Function(){public void f() { -- onComplete(); -- }}); ++ g.transition(p, duration, easing, delay, new Function() { ++ public void f() { ++ onComplete(); ++ } ++ }); } } diff --cc gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/EventsListener.java index a19142b8,bfb24d2c..7d88ac7c --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/EventsListener.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/EventsListener.java @@@ -48,50 -45,69 +48,50 @@@ import java.util.Map */ public class EventsListener implements EventListener { - public interface SpecialEvent { - String getDelegateType(); - - String getOriginalType(); - - Function createDelegateHandler(Function originalHandler); - } - /** -- * Used for simulating mouseenter and mouseleave events ++ * Used for simulating mouseenter and mouseleave events. */ - public static class MouseSpecialEvent implements SpecialEvent { - - private String originalType; - private String delegateType; - - public MouseSpecialEvent(String originalType, String delegateType) { - this.originalType = originalType; - this.delegateType = delegateType; - } - - public String getDelegateType() { - return delegateType; - } - - public String getOriginalType() { - return originalType; - } - - public Function createDelegateHandler(Function originalHandler) { - return new SpecialMouseEventHandler(originalHandler); + private static class MouseSpecialEvent extends DefaultSpecialEvent { + public MouseSpecialEvent(final String type, String delegateType) { + super(type, delegateType); + handler = new Function() { + public boolean f(Event e, Object... arg) { + EventTarget eventTarget = e.getCurrentEventTarget(); + Element target = eventTarget != null ? eventTarget. cast() : null; + + EventTarget relatedEventTarget = e.getRelatedEventTarget(); + Element related = relatedEventTarget != null ? relatedEventTarget. cast() : null; + + if (related == null || (related != target && !GQuery.contains(target, related))) { + getInstance(target).dispatchEvent(e, type); + } + return true; + }; + }; } } - private interface HandlerWrapper { - Function getOriginalHandler(); - } - private static class SpecialMouseEventHandler extends Function implements HandlerWrapper { - - private Function delegateHandler; - - public SpecialMouseEventHandler(Function originalHandler) { - this.delegateHandler = originalHandler; - } - - @Override - public boolean f(Event e, Object... data) { - EventTarget eventTarget = e.getCurrentEventTarget(); - Element target = eventTarget != null ? eventTarget. cast() : null; - - EventTarget relatedEventTarget = e.getRelatedEventTarget(); - Element related = relatedEventTarget != null ? relatedEventTarget. cast() : null; - - // For mousenter/leave call the handler if related is outside the target. - if (related == null || (related != target && !GQuery.contains(target, related))) { - return delegateHandler != null ? delegateHandler.f(e, data) : false; + /** - * Utility class to split a list of events with or without namespaces ++ * Utility class to split a list of events with or without namespaces. + */ + public static class EventName { + public final String nameSpace; + public final String eventName; + public EventName(String n, String e) { + nameSpace = n; + eventName = e; + } + + public static List split(String events) { + List ret = new ArrayList(); + String[] parts = events.split("[\\s,]+"); + for (String event : parts) { + String[] tmp = event.split("\\.", 2); + String eventName = tmp[0]; + String nameSpace = tmp.length > 1 ? tmp[1] : null; + ret.add(new EventName(nameSpace, eventName)); } - - return false; - } - - public Function getOriginalHandler() { - return delegateHandler; + return ret; } } @@@ -194,7 -214,7 +193,7 @@@ } /** -- * Add a {@link BindFunction} for a specific css selector ++ * Add a {@link BindFunction} for a specific css selector. */ public void addBindFunctionForSelector(String cssSelector, BindFunction f) { JsObjectArray bindFunctions = bindFunctionBySelector.get(cssSelector); @@@ -277,10 -297,10 +276,10 @@@ } /** -- * Remove the BindFunction associated to this cssSelector ++ * Remove the BindFunction associated to this cssSelector. */ - public void removeBindFunctionForSelector(String cssSelector, String nameSpace, String originalEventName) { - if (nameSpace == null && originalEventName == null) { + public void removeBindFunctionForSelector(String cssSelector, String nameSpace) { + if (nameSpace == null) { bindFunctionBySelector.delete(cssSelector); } else { JsObjectArray functions = bindFunctionBySelector.get(cssSelector); @@@ -306,7 -328,7 +304,7 @@@ } /** -- * Tell if no {@link BindFunction} are linked to this object ++ * Tell if no {@link BindFunction} are linked to this object. * * @return */ @@@ -322,7 -344,7 +320,7 @@@ /** * Return the element whose the listener fired last. It represent the context element where the -- * {@link LiveBindFunction} was binded ++ * {@link LiveBindFunction} was binded. * */ private Element getCurrentEventTarget(Event e) { @@@ -336,7 -358,7 +334,7 @@@ } /** -- * Return the element that was the actual target of the element ++ * Return the element that was the actual target of the element. */ private Element getEventTarget(Event e) { EventTarget eventTarget = e.getEventTarget(); @@@ -529,10 -586,10 +526,10 @@@ } private void maybeRemoveLiveBindFunction(LiveBindFunction liveBindFunction, String cssSelector, - int eventbits, String eventName, String nameSpace, String originalEventName) { + int eventbits, String eventName, String nameSpace) { if (liveBindFunction != null) { - liveBindFunction.removeBindFunctionForSelector(cssSelector, nameSpace, originalEventName); - if (liveBindFunction.isEmpty()){ + liveBindFunction.removeBindFunctionForSelector(cssSelector, nameSpace); - if (liveBindFunction.isEmpty()){ ++ if (liveBindFunction.isEmpty()) { if (eventbits != BITLESS) { liveBindFunctionByEventType.remove(eventbits); } else { diff --cc gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java index 19f251b4,a93e5491..8493fd81 --- a/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java +++ b/gwtquery-core/src/main/java/com/google/gwt/query/client/plugins/events/GqEvent.java @@@ -88,9 -97,9 +88,9 @@@ public class GqEvent extends Event * */ public final int pageX() { -- if (getTouches() != null && getTouches().length() > 0){ ++ if (getTouches() != null && getTouches().length() > 0) { return getTouches().get(0).getPageX(); -- }else{ ++ } else { return getClientX() + GQuery.document.getScrollLeft(); } } @@@ -100,9 -109,9 +100,9 @@@ * */ public final int pageY() { -- if (getTouches() != null && getTouches().length() > 0){ ++ if (getTouches() != null && getTouches().length() > 0) { return getTouches().get(0).getPageY(); -- }else{ ++ } else { return getClientY() + GQuery.document.getScrollTop(); } } diff --cc gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonBuilderHandler.java index 00000000,8d9b9a4c..adbdd233 mode 000000,100644..100644 --- 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 @@@ -1,0 -1,328 +1,346 @@@ ++/* ++ * 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.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 Object jsonArrayToList(JsonArray j, Class ctype, boolean isArray) { + List l = new ArrayList(); + 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 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 clz = (Class) 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 validAttrs = getAttributeNames(type.getMethods()); + Hashtable 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 getAttributeNames(Method[] methods) { + HashSet valid = new HashSet(); + + 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 getJsonBuilders(Method[] methods) { + Hashtable ispropertyGetters = new Hashtable(); + + 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; + } + } diff --cc gwtquery-core/src/main/java/com/google/gwt/query/vm/JsonFactoryJre.java index 0d9763c2,66a8f5bc..5a976f3f --- 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 @@@ -49,10 -32,10 +32,8 @@@ import elemental.json.impl.JreJsonNull * 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(); + public class JsonFactoryJre implements JsonFactory { - - /** * Although functions cannot be serialized to json we use JsonBuilders * or IsProperties objects which can be used as settings in Ajax.