当前位置: 首页 > 知识库问答 >
问题:

在GraalVM Polyglot上下文中从JavaScript访问Java对象

郑正文
2023-03-14

在GraalVM CE上跑步。

openjdk version "11.0.5" 2019-10-15
OpenJDK Runtime Environment (build 11.0.5+10-jvmci-19.3-b05-LTS)
OpenJDK 64-Bit GraalVM CE 19.3.0 (build 11.0.5+10-jvmci-19.3-b05-LTS, mixed mode, sharing)

案例一:

import org.graalvm.polyglot.Context;

public class Test {

    static class Data {
        public String name = "HelloWorld";
        public String getName() {
            return this.name;
        }
    }

    public static void main(String[] args) {
        Context context = Context.newBuilder("js").allowHostAccess(true).build();
        context.getBindings("js").putMember("d", new Data());

        context.eval("js", "var x = d.name");

        System.out.println(
                context.getBindings("js").getMember("x").asString()
        );
    }
}

结果:

null

为什么?

据我所知,d正确通过:

((Data) context.getBindings("js").getMember("d").as(Data.class)).name

返回"HelloWorld"

案例2:

context.eval("js", "d.getName()");

例外情况

Exception in thread "main" TypeError: invokeMember (getName) 
on JavaObject[task.Test$Data@35a3d49f (task.Test$Data)] failed due to: 
Unknown identifier: getName

但是getName是公共的。。。发生了什么?

共有3个答案

章晋鹏
2023-03-14

GraalVM JavaScript默认强制执行严格的沙箱规则,其中之一是JavaScript代码不能访问主机Java对象,除非用户明确允许。允许代码访问context.eval(“js”、“d.getName()”)的最简单方法是传递选项polyglot.js.allowAllAccess=true,如下链接所述:

GraalVM JavaScript脚本引擎实现

请看一下示例:

import org.graalvm.polyglot.Context;

public class Test {

    static class Data {
        public String name = "HelloWorld";
        public String getName() {
            return this.name;
        }
    }

    public static void main(String[] args) {
        Context context = Context.newBuilder("js").allowHostAccess(true).build();
        context.getBindings("js").putMember("d", new Data());

        context.eval("js", "var x = d.getName()");

        System.out.println(
                context.getBindings("js").getMember("d").as(Data.class)).name
        );
    }
}
毛正浩
2023-03-14

当您使用上下文并向其中添加Java对象时,在场景后面,TruffleApp内部的IntropLibrary会创建一个HostObject并将其与该对象关联。这意味着您不使用对象本身,而是使用包装器对象。

调用getMember()方法时,IntropLibrary只能访问托管对象中公开可用的字段和方法。由于内部类具有默认访问权限(无访问修饰符),因此API无法找到其成员,即使它们是公共的。(类的成员不能拥有比其类本身更广泛的访问权限)。

要解决这个问题,你所要做的就是公开你的内心世界

import org.graalvm.polyglot.Context;

public class Test {

  public static class Data {
    public String name = "HelloWorld";
    public String getName() {
        return this.name;
    }
  }

  public static void main(String[] args) {
    Context context = Context.newBuilder("js").allowHostAccess(true).build();
    context.getBindings("js").putMember("d", new Data());

    context.eval("js", "var x = d.name;");

    System.out.println(
        context.getBindings("js").getMember("x").asString()
    );
  }
}
都阳
2023-03-14

您需要用@HostAccess注释类字段和方法。出口

默认情况下,只有使用@HostAccess注释的公共类、方法和字段。可以使用来宾语言进行导出。可以使用上下文自定义此策略。建设者构造上下文时允许访问(主机访问)。

使用JavaScript中的Java对象的示例:

 public class JavaRecord {
     @HostAccess.Export public int x;    
     @HostAccess.Export
     public String name() {
         return "foo";
     }
 }

或者,您可以使用GraalVM JSR-223 ScriptEngine

GraalVM JavaScript提供了符合JSR-223的javax。剧本脚本引擎实现。请注意,这是出于遗留原因而提供的功能,以便为当前基于ScriptEngine的实现提供更轻松的迁移。我们强烈鼓励用户使用该组织。格拉尔文。通晓多种语言。上下文接口

要通过绑定设置选项,请使用绑定。在初始化引擎的脚本上下文之前放置(,true)。请注意,即使是对Bindings#get(String)的调用也可能导致上下文初始化。下面的代码显示了如何启用polyglot。js。允许通过绑定访问:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
bindings.put("polyglot.js.allowHostAccess", true);
bindings.put("polyglot.js.allowHostClassLookup", (Predicate<String>) s -> true);
bindings.put("javaObj", new Object());
engine.eval("(javaObj instanceof Java.type('java.lang.Object'));"); // would not work 

如果没有allowHostAccess和allowHostClassLookup,如果用户调用例如engine,该示例将不起作用。评估(“var x=1;”)在调用绑定之前。put(“polyglot.js.allowostaccess”,true);,因为对eval的任何调用都会强制进行上下文初始化。

 类似资料:
  • 问题内容: 问题答案: 你不能 JavaScript中没有向上关系。 举个例子: 现在,单个数组对象具有两个“父级”。 您可以做的是:

  • 问题内容: 有没有可以让我在Firefox中操纵文件下载对话框的API?(我想访问用户做某事时显示的内容,而不是自己发起)。 我想做的是从Selenium访问此对话框(我不确定Selenium的“特权模式”是否足以访问chrome接口)。 问题答案: 从来没听说过。但是您可以将Firefox配置为自动开始下载并将文件保存在特定位置。然后,您的测试可以检查文件是否实际到达。

  • 问题内容: 就像是 这是我想象的格式,但事实并非如此。什么会退回到对象的父级? 问题答案: JavaScript本身不提供此功能。而且我怀疑您是否可以创建这种类型的功能。例如: 鲍比属于谁?

  • 我有一些测试(我没有编写它们,我正在维护它们)使用spring ContextConfiguration注释来提供应用程序上下文: 总之,有几个问题。我不太熟悉spring自定义上下文位置,这些位置不指定file:/或classpath:/。这是什么意思?这个测试类路径上有很多同名的资源。都上膛了吗?如果不是,Spring如何知道要加载哪个? 第二,有没有一种方法可以通过编程方式访问以这种方式连接

  • 问题内容: 我试图将一些Scala代码注入到现有的Java应用程序中。(所以,话说回来,我想要更多的乐趣)。 我在Scala中创建一个单例的东西 现在,在OldJava.java中 我应该填写什么以便Java调用showMyPower方法?我尝试了两者 ,但没有任何效果。 (使用Jad反编译类文件,除了胡说八道之外,什么都没给我显示。) 编辑 我删除了声明,scala产生了预期的静态方法。(呼吁工