Javafx WebView无法访问类的成员...使用修饰符" public"

时间:2016-09-26 14:01:04

标签: javascript java javafx webview

在我正在开发的项目中,我需要定义一个抽象类,其中包含在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电话。

Packagetwo

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()");
    }
}

Packageone

package packageone;

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

Index.html只是一个标准的html页面,可以使用<p>标记成功加载,表明页面已加载。

任何想法为什么Javascript环境无法调用我在packagetwo中实现的方法?

编辑:

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

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

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

1 个答案:

答案 0 :(得分:0)

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

如果你在packagetwo中创建一个公共实现,即使是Calls中的内部类,然后创建一个通过它的实例,它也会按预期工作。