添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
高大的上铺  ·  Strings - C# ...·  3 年前    · 
道上混的键盘  ·  JavaScript get ...·  3 年前    · 
刚毅的灭火器  ·  Microsoft .NET ...·  3 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams
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)

Case 1:

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

Result:

As I can understand, d passed correctly:

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

returns "HelloWorld".

Case 2:

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

Exception

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

But getName is public... What's wrong?

When you use a context and add a Java Object to it, behind the scene, the IntropLibrary inside TruffleApi creates a HostObject and associate it with that object. This means that you don't use the object itself but rather a wrapper object.

When you call the getMember() method, the IntropLibrary can only access fields and methods of the hosted object that are publicly available. Since your inner class has default access (no access modifier), the API cannot find its members even though they are public. (a member of a class cannot have broader access than its class itself).

To solve this issue, all you have to do is make you inner class public

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

By default only public classes, methods, and fields that are annotated with @HostAccess.Export are accessible to the guest language. This policy can be customized using Context.Builder.allowHostAccess(HostAccess) when constructing the context.

Example using a Java object from JavaScript:

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

Alternatively, you can use GraalVM JSR-223 ScriptEngine

GraalVM JavaScript provides a JSR-223 compliant javax.script.ScriptEngine implementation. Note that this is feature is provided for legacy reasons in order to allow easier migration for implementations currently based on a ScriptEngine. We strongly encourage users to use the org.graalvm.polyglot.Context interface

To set an option via Bindings, use Bindings.put(, true) before the engine's script context is initialized. Note that even a call to Bindings#get(String) may lead to context initialization. The following code shows how to enable polyglot.js.allowHostAccess via Bindings:

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 
  

without allowHostAccess and allowHostClassLookup This example would not work if the user would call e.g. engine.eval("var x = 1;") before calling bindings.put("polyglot.js.allowHostAccess", true);, since any call to eval forces context initialization.

At first I don't want use JSR-223, because as said in your citation "this is feature is provided for legacy reasons". And secondly I tried such way without success. I am looking for solution with polyglot Context. – Woland Nov 25, 2019 at 6:38

GraalVM JavaScript enforces strict sandboxing rules by default, one of them being that JavaScript code cannot access host Java objects unless it is explicitly allowed by the user. The simplest way to allow your code to access context.eval("js", "d.getName()") is to pass the option polyglot.js.allowAllAccess=true as described in below link:

GraalVM JavaScript ScriptEngine implementation

Have a look at the Sample:

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
                Notice that I already use allowHostAccess(true). I also tried settings from your link Value bindings = context.getBindings("js"); bindings.putMember("polyglot.js.allowHostAccess", true); bindings.putMember("polyglot.js.allowHostClassLookup", (Predicate<String>) s -> true);. No success.
– Woland
                Nov 24, 2019 at 20:58

To get full access to a java object in the usual js way, you can use the sj4js library.

This example is taken from the documentation...

public class TestObject extends JsProxyObject {
    // the property of the object
    private String name = "";
    // the constructor with the property 
    public TestObject (String name) {
        super ();
        this.name = name;
        // we hvae to initialize the proxy object
        // with all properties of this object
        init(this);
    // this is a mandatory override, 
    // the proxy object needs this method 
    // to generate new objects if necessary
    @Override
    protected Object newInstance() {
        return new TestClass(this.name);
    // the setter for the property name
    public void setName (String s) {
        this.name = s;
    // the getter for the property name
    public String getName () {
        return this.name;

And you can access this object as you would access a java object.

try (JScriptEngine engine = new JScriptEngine()) {
    engine.addObject("test", new TestClass("123"));
    engine.exec("test.name");
    // returns "123"
    engine.exec("test['name']")
    // returns "123"
    engine.exec("test.name = '456'")   
    engine.exec("test.name");
    // returns "456"
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid …

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.