【问题标题】:Possibility to call nonstatic gwt java method from javascript可以从 javascript 调用非静态 gwt java 方法
【发布时间】:2012-05-04 11:47:33
【问题描述】:

一般目标:从 javascript 调用一些非静态 java 方法

说明: 在 Java Applet 代码中的 DOM 上找到 gwt 的小部件并调用它的 java 方法(非静态)


JSObject win = JSObject.getWindow(this);
JSObject doc = (JSObject) win.getMember("document");
JSObject gwtWidget = (JSObject) doc.call("getElementsByName", widgetName);

//todo: have possibility to call `exported` java method over here, smth like:
//Object[] params = new Object[1];
//params[0] = widgetName;
//Object result = gwtWidget.call("exportedJavaMethod", params);

//todo: or just call global ($wnd) static JSNI bridge method:
//Object result = win.call("exportedJavaMethod", params);
//

问题是:我可以通过小部件的 id 找到小部件,但它是 DivElement,它没有任何导出的实例方法。

我的小部件类是可导出的(gwt-export):


@Export(value="somewidget")
public class SomeWidget extends SimplePanel implements ..., Exportable {
    private final String id = "id_some_widget_" + count++;
    private static int count = 0;

    public SomeWidget () {
        getElement().setAttribute("name", id);
        getElement().setId(id);
    }
    ...

    public static Element getInstanceById(String elementId) {
        Element someWidget= DOM.getElementById(elementId);
        return someWidget;
    }

    public String getSomeInstancedData() {
        return "useful_inner_data" + this.id;
    }

所以,例如,我想找到添加到 DOM 的具体小部件并在 javascript 中调用非静态方法 getSomeInstancedData()。有可能吗?

假设:


var someWidget = document.getElementById(widgetId);
alert(someWidget.getSomeInstancedData());

//or:
var someWidgetExported = com.mypackage.widgets.somewidget.getInstanceById(listenerId);
alert(someWidgetExported.getSomeInstancedData());

在基本模块中我写:


ExporterUtil.exportAll();

有一个 View(ViewWithSomeWidget.ui.xml) 包含这个小部件:

... 基地:形式 base:SomeWidget ui:field="someWidget" ... ... /base:SomeWidget ...

当 SomeWidget 没有实现 Exportable 时,项目运行良好,但我无法调用找到的小部件的 DIV 元素的非静态方法。

到那时,为了解决SomeWidget实现Exportable的问题,progect由于ClassCastException使用延迟绑定而无法很好地显示带有SomeWidget的View:


ClassCastException: com.mypackage.widgets.SomeWidgetExporterImpl cannot be cast to com.mypackage.widgets.SomeWidget

那么,可能还有其他方法可以找到小部件的 javascript 对象并将其称为导出的 java 方法吗?无论如何,任何想法都非常受欢迎。

【问题讨论】:

    标签: java javascript gwt jsni exporter


    【解决方案1】:

    您可以声明一个 javascript 函数,该函数将触发非静态方法。

    例如:

    package com.example;
    public class Layout extends VLayout() {
        private String nonStaticVar = "nonStaticVar";
        public Layout() {
            declareMethod(this);
        }
    
        //Method which declares non-static method in javascript
        public native void declareMethod(Layout layout) /*-{
            var layout = layout;
            $wnd.doSomething = function(someString) {
                layout.@com.example.Layout::doSomething(Ljava/lang/String;)(someString);
            }
        }-*/;
    
        //Non static method which is being called
        public String doSomething(String someString) {
            //Do something, e.g. set var in this instantiated class, or output stuff
            this.nonStaticVar = someString;
            Window.alert(someString);
        }
    }
    

    现在,打电话 doSomething("bla"); from javascript 会调用你的非静态方法。

    【讨论】:

      【解决方案2】:

      你可以在 div 元素上定义一个自己的jsmethod,它可以调用一个widget-method

      @Export(value="somewidget")
      public class SomeWidget extends SimplePanel implements ..., Exportable {
          private final String id = "id_some_widget_" + count++;
          private static int count = 0;
      
          public SomeWidget () {
              getElement().setAttribute("name", id);
              getElement().setId(id);
              attachInstanceHook(getElement());
          }
          ...
      
          public String getSomeInstancedData() {
              return "useful_inner_data" + this.id;
          }
      
      
          private native void attachInstanceHook(Element element) /*-{
              var elem = element;
              var widget = this;
              elem.getWidgetData = function () {
                  widget.@your.package.name.SomeWidget::getSomeInstancedData()();
              };
      
          }-*/;
      

      您的 js 代码应如下所示:

      var someWidget = document.getElementById(widgetId);  //the id of the div element
      alert(someWidget.getWidgetData());
      

      【讨论】:

        【解决方案3】:

        与其尝试通过其 DOM 元素获取小部件,不如先将其 Java 实例注入全局范围并引用它:

        public class SomeWidget extends SimplePanel implements ..., Exportable {
        
            //...
        
            public SomeWidget () {
                getElement().setAttribute("name", id);
                getElement().setId(id);
        
                attachToGlobalScope(id, this);
            }
        
            private native void attachToGlobalScope(String id, SomeWidget instance) /*-{
                $wnd.shared[id] = instance;
            }-*/;
        
            //...
        }
        

        稍后,在 Applet API 层更新相应的 fetch:

        JSObject win = JSObject.getWindow(this);
        JSObject shared = (JSObject) win.getMember("shared");
        Widget widgetRef = (Widget) shared.getMember(widgetId);
        

        免责声明:这种有点歪曲的解决方案依赖于 JavaScript 全局范围变量,这通常被认为是不好的做法,但这里是唯一的公共范围,因此被滥用于对象存储。

        【讨论】:

        • 问题是 getElement() 返回的 DIV 元素没有任何声明的 java 方法...实际上,我已经尝试过几乎相同的尝试。我暂时使用的当前解决方案是声明静态方法(桥),该方法将使用有用的包装数据触发 GWTEvent。 Widget 只是通过订阅它的构造函数来监听这样的事件。每个 Widget 实例都会收到一个事件并通过它自己的 Id 过滤它。
        • @rauch,我理解将另一个答案勾选为已接受,因为它可以更好地解决问题,但为什么还要删除赞成票?
        猜你喜欢
        • 1970-01-01
        • 2016-01-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多