【问题标题】:Javafx WebView can not access a member of class ... with modifiers "public"Javafx WebView 无法使用修饰符“public”访问类的成员...
【发布时间】:2016-09-26 14:01:03
【问题描述】:

在我正在进行的一个项目中,我需要定义一个抽象类,其中包含一些在 packageone 中实现的方法。在 packagetwo 中,其余的抽象方法将在类被实例化时实现。然后该实例在 JavaFX webview 中暴露给 Javascript 代码。 (来自 Oracle 的在线示例 - https://blogs.oracle.com/javafx/entry/communicating_between_javascript_and_javafx

我的问题是,packagetwo 中实现的方法不能从 Javascript 环境中调用。我收到以下错误:

Exception in thread "JavaFX Application Thread" netscape.javascript.JSException: java.lang.IllegalAccessException: Class sun.reflect.misc.Trampoline can not access a member of class packagetwo.MainWindow$1 with modifiers "public"
    at com.sun.webkit.dom.JSObject.fwkMakeException(JSObject.java:128)
    at com.sun.webkit.WebPage.twkExecuteScript(Native Method)
    at com.sun.webkit.WebPage.executeScript(WebPage.java:1439)
    at javafx.scene.web.WebEngine.executeScript(WebEngine.java:982)
    at packagetwo.MainWindow.makeUpCall(MainWindow.java:130)
    at packagetwo.MainWindow.access$000(MainWindow.java:22)
    at packagetwo.MainWindow$2.changed(MainWindow.java:83)
    at packagetwo.MainWindow$2.changed(MainWindow.java:68)
    at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.ReadOnlyObjectPropertyBase.fireValueChangedEvent(ReadOnlyObjectPropertyBase.java:74)
    at javafx.beans.property.ReadOnlyObjectWrapper.fireValueChangedEvent(ReadOnlyObjectWrapper.java:102)
    at javafx.beans.property.ObjectPropertyBase.markInvalid(ObjectPropertyBase.java:112)
    at javafx.beans.property.ObjectPropertyBase.set(ObjectPropertyBase.java:146)
    at javafx.scene.web.WebEngine$LoadWorker.updateState(WebEngine.java:1260)
    at javafx.scene.web.WebEngine$LoadWorker.dispatchLoadEvent(WebEngine.java:1371)
    at javafx.scene.web.WebEngine$LoadWorker.access$1200(WebEngine.java:1253)
    at javafx.scene.web.WebEngine$PageLoadListener.dispatchLoadEvent(WebEngine.java:1240)
    at com.sun.webkit.WebPage.fireLoadEvent(WebPage.java:2400)
    at com.sun.webkit.WebPage.fwkFireLoadEvent(WebPage.java:2244)
    at com.sun.webkit.network.URLLoader.twkDidFinishLoading(Native Method)
    at com.sun.webkit.network.URLLoader.notifyDidFinishLoading(URLLoader.java:838)
    at com.sun.webkit.network.URLLoader.lambda$didFinishLoading$96(URLLoader.java:829)
    at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalAccessException: Class sun.reflect.misc.Trampoline can not access a member of class packagetwo.MainWindow$1 with modifiers "public"
    at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
    at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
    at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
    at java.lang.reflect.Method.invoke(Method.java:491)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at com.sun.webkit.Utilities.lambda$fwkInvokeWithContext$55(Utilities.java:94)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.webkit.Utilities.fwkInvokeWithContext(Utilities.java:94)
    ... 29 more

虽然在 packageone 中实现的调用方法工作正常。从 Java 调用这两组方法也可以正常工作。以下是我的课程和 Javascript 调用。

包二

package packagetwo;

import packageone.Calls;



import java.io.File;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;


public class MainWindow implements Initializable
{

     @FXML
    private BorderPane mainWindow;

    @FXML
    private WebView mainWebView;

    @FXML
    private AnchorPane mainWebViewLayout;

    @Override
    public void initialize(URL url, ResourceBundle rb)
    {           
        Calls jc = new Calls()
        {
            @Override
            public void aMethod1()
            {
                System.out.printf("Calls: Abstract Method Impl 1 Called.\n");
            }
        };

        // Add new load complete listener.
        ChangeListener<Worker.State> onLoadComplete = buildOnLoadCompleteListener(mainWebView, jc);
        mainWebView.getEngine()
                .getLoadWorker()
                .stateProperty()
                .addListener(
                    onLoadComplete);


        // Attempt to load the current web package.
        mainWebView.getEngine().load("file:///" + new File("index.html").getAbsolutePath());

    }

    private ChangeListener<Worker.State> buildOnLoadCompleteListener(
            WebView webview, Calls javaUpCalls)
    {
        return new ChangeListener<Worker.State>()
        {
            @Override
            public void changed(
                    ObservableValue<? extends Worker.State> ov,
                    Worker.State lastState, Worker.State currentState)
            {
                if (currentState == Worker.State.SUCCEEDED)
                {                       
                    // Hook up Java up calls in the Javascript environment.
                    JSObject jsEnvironment = (JSObject) webview.getEngine().executeScript("window");
                    jsEnvironment.setMember("JavaUpCalls", javaUpCalls);

                    makeUpCall(webview);
                }
            }
        };
    }

    private void makeUpCall(WebView webview)
    {           
        String setUpUpCall = 
            "function makeAnUpCall()" +
            "{" +
                "if(typeof JavaUpCalls !== \"undefined\")" +
                "{" + 
                    "JavaUpCalls.method2();" +
                    "JavaUpCalls.aMethod1();" +
                "}" +
            "}";


        webview.getEngine().executeScript(setUpUpCall);
        webview.getEngine().executeScript("makeAnUpCall()");
    }
}

一揽子

package packageone;

public abstract class Calls()
{
    public abstract void aMethod1();
    public void method2()
    {
        System.out.printf("Calls: Method 1 Called.\n");
    }
}

Index.html 只是一个标准的 html 页面,它使用 &lt;p&gt; 表示页面已加载的标签成功加载。

知道为什么 Javascript 环境不能调用我在 packagetwo 中实现的方法吗?

编辑:

我在网上研究了一下,发现了这个 StackOverflow 问题:

我尝试了那里列出的解决方案(在 packagetwo 方法实例上调用 setAccessible(true)),但仍然抛出错误。

我也尝试过从 packageone 初始化和调用 Javascript 方法,但仍然出现错误。

【问题讨论】:

    标签: javascript java javafx webview


    【解决方案1】:

    Calls 的匿名实现不能作为公共类使用,因此 javascript 引擎无法访问它。

    如果您在 packagetwo 中创建公共实现,即使作为 MainWindow 中的内部类,然后创建该实例以通过它,它也会按您的预期工作。

    【讨论】:

    • 现在说得通了。谢谢你的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-02
    • 1970-01-01
    • 2012-08-15
    • 2012-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多