From: Edwin C. <com...@gm...> - 2009-08-13 20:09:23
|
Hi Jing Xia, I have been playing a bit with implemeting one or more invoke methods. When functions are invoked it is on OpenLayers objects (The getProperty/setProperty methods are for the config objects, and it's never necessary to invoke functions on config objects). Often these functions return values and I think it may get messy to get the return values by their correct type. Maybe you have some suggestions when you looking at what I have written below, since it looks like you were already using code to invoke functions (or did you create that after seeing getProperty/setProperty?). What did you do if a function returned a String, floating point number, or integer? Please read on to see what I mean. I found that I needed the following to code to invoke toString of Size and have it return a String (for an easy example and for briefness I made a variant to invoke functions that do not take arguments): in JSObjectHelper: public static native Object invoke(JSObject object, String name) /*-{ return object[name].apply(object); }-*/; in JSObject: public final Object invoke(String name) { return JSObjectHelper.invoke(this, name); }; invoking toString of Size: public String toString(){ return (String) getJSObject().invoke("toString"); } As you might have notice an Object is returned.by the JSObjectHelper/JSObject return methods. Returning a JSObject did not work, because that cannot be cast to a String and I also could not get a working narrowToString function on JSObject. It is a bit vague to my why returning Object did work. As an implementation of narrowToString I tried: public static native String narrowToString(JSObject object) /*-{ return object; //Gives a ClassCast exception }-*/; Although this works, and I can image it works with your way to pass arguments, I can foresee some uglyness when an integer or float is returned from the invoked function. Right now a lot of the API works with primitives and there is a mismatch between Object and primitives. I'd rather avoid autoboxing so then you may get things like: Float f = (Float) getJSObject().invoke("getHeight"); return f.floatValue(); An uglier problem is how to combine this with the possibility that a complex Javascript object is returned, because that would have to be returned as a JSObject. In Java functions with the same signature but different return tyehpes are not allowed, so we cannot have both: public final Object invoke(String name){ ... }; public final JSObject invoke(String name){ ... }; I would like to hear your thoughts on how we can make Greetings, Edwin Commandeur P.S. If a JSObject comes back that would just have to be narrowed to the appropriate type, for example: Bounds.narrowToBounds(getJSObject().invoke("getBounds")); Hi Jing Xia, > > The reason to extend JavaScriptObject and to have setProperty and > getProperty methods is because OpenLayers works a lot with config objects. > These config objects are not existing javascript objects so they necessitate > creating javascript objects from scratch, which in turn requires JSNI. To > reduce the amount of JSNI the setProperty/getProperty methods were > introduced. > > The setProperty and getProperty methods on JSObject can already be used to > set methods (or rather functions in javascript) on the JSObject via > setProperty(obj:JSObject). A function is a JSObject, see for example > setFormatOutput on 'MousePositionOptions' and formatOutput on > 'MousePositionImpl' . > > The Impl classes will be necessary at least for create methods that call > existing constructors. > > I need to take a closer look at your code to understand the impact. > > There are already helper classes for working with Arrays by the way. Notice > that an Array created by GWT does not pass the instanceof Array test in > javascript (that is why there are relay methods in the javascript file that > comes with GWT-OL) > > Greetings, > Edwin > > 2009/8/12 岚山.隐 <642...@qq...> > > I spend hours to see the source code of the project. I think it is very >> cool when I saw the encapsulated methods "setProperty" and "getPropertyAs*" >> which makes all set and get javascript property code come to one place. >> Then I think about for minutes, if property can, why not method! So I >> started to encapsulate method just as how you have done on property. >> The following is my code, whether it could be used on this project? I >> think that piece this together with the JSObject class will disappear all >> the "*Impl" classes in this project. >> >> >> package com.yingxia.client.jsni; >> >> import com.google.gwt.core.client.JavaScriptObject; >> >> public class JavaScriptObjectWrapper extends JavaScriptObject { >> >> protected JavaScriptObjectWrapper() { >> } >> >> public static native JavaScriptObjectWrapper createNew() /*-{ >> return {}; >> }-*/; >> >> public final JavaScriptObjectWrapper invokeJSMethod(String methodName, >> Object... objs) { >> JavaScriptObjectWrapper arguments = >> JavaScriptArrayHelper.toJSArray(objs); >> return JavaScriptObjectWrapperImpl.invokeJSMethod(this, methodName, >> arguments); >> } >> >> } >> >> package com.yingxia.client.jsni; >> >> public class JavaScriptObjectWrapperImpl { >> >> public static native JavaScriptObjectWrapper >> invokeJSMethod(JavaScriptObjectWrapper jsObject, String methodName, >> JavaScriptObjectWrapper arguments) /*-{ >> return jsObject[methodName].apply(jsObject, arguments); >> }-*/; >> >> } >> >> package com.yingxia.client.jsni; >> >> public class JavaScriptArrayHelper { >> /** >> * >> * @param objs : must be primitive type or JavaScriptObject, now just >> support few you can extend >> * @return >> */ >> public static JavaScriptObjectWrapper toJSArray(Object... objs) { >> >> JavaScriptObjectWrapper jsArray = createJSArray(); >> >> for(int i = 0; i < objs.length; i++) { >> setJSArray(jsArray, i, objs[i]); >> } >> >> return jsArray; >> } >> >> private static native JavaScriptObjectWrapper createJSArray() /*-{ >> return []; >> }-*/; >> >> private static void setJSArray(JavaScriptObjectWrapper jsArray, int >> index, Object value) { >> if(value.getClass().equals(java.lang.Integer.class)) { >> setJSArray(jsArray, index, (int) Integer.valueOf(value.toString())); >> } >> if(value.getClass().equals(java.lang.Float.class)) { >> setJSArray(jsArray, index, (float) Float.valueOf(value.toString())); >> } >> if(value.getClass().equals(java.lang.Double.class)) { >> setJSArray(jsArray, index, (double) Double.valueOf(value.toString())); >> } >> if(value.getClass().equals(java.lang.Boolean.class)) { >> setJSArray(jsArray, index, (boolean) >> Boolean.valueOf(value.toString())); >> } >> if(value.getClass().equals(java.lang.String.class)) { >> setJSArray(jsArray, index, value.toString()); >> } >> if(value.getClass().equals(JavaScriptObjectWrapper.class)) { >> setJSArray(jsArray, index, (JavaScriptObjectWrapper) value); >> } >> } >> >> private static native void setJSArray(JavaScriptObjectWrapper jsArray, >> int index, int value) /*-{ >> jsArray[index] = value; >> }-*/; >> >> private static native void setJSArray(JavaScriptObjectWrapper jsArray, >> int index, float value) /*-{ >> jsArray[index] = value; >> }-*/; >> >> private static native void setJSArray(JavaScriptObjectWrapper jsArray, >> int index, double value) /*-{ >> jsArray[index] = value; >> }-*/; >> >> private static native void setJSArray(JavaScriptObjectWrapper jsArray, >> int index, boolean value) /*-{ >> jsArray[index] = value; >> }-*/; >> >> private static native void setJSArray(JavaScriptObjectWrapper jsArray, >> int index, String value) /*-{ >> jsArray[index] = value; >> }-*/; >> >> private static native void setJSArray(JavaScriptObjectWrapper jsArray, >> int index, JavaScriptObjectWrapper value) /*-{ >> jsArray[index] = value; >> }-*/; >> } >> >> >> Greetings, >> ying xia >> > > |