|
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
>>
>
>
|