Ошибка при попытке доступа к членам класса (с помощью Rhino)

Попытка создать ссылку Java/JS с помощью Rhino с двумя очень простыми объектами, один из которых имеет в качестве одного члена экземпляр второго класса.

Запуск приведенного ниже кода дает следующую ошибку:

org.mozilla.javascript.EcmaError: TypeError: не удается найти значение по умолчанию для объекта.

Кажется, проблема заключается в доступе к элементу «a» из второго объекта. Я также пробовал с таким геттером:

public Object jsGet_a() {
 return Context.toObject(a, this);
}

но я получаю ту же ошибку.

новый A().doSmth(); работает нормально и выводит "Я что-то делаю" new B().a.doSmth(); вызывает ошибку

Может ли кто-нибудь помочь мне с возможным решением для этого?

Спасибо!


public class Test {

    public static class A extends ScriptableObject implements Scriptable {

            public A() {
            };

            public String getClassName() {
                    return "A";
            }

            public void jsFunction_doSmth() {
                    System.out.println("I'm doing something");
            };

    }

    public static class B extends ScriptableObject implements Scriptable {

            private A a = new A();

            public B() {
            };

            public String getClassName() {
                    return "B";
            }

            public void jsConstructor() {
            }

            public A jsGet_a() {
                    return a;
            }

    }

    public static void main(String[] args) {
            try {
                    Context cx = Context.enter();

                    Scriptable scope = cx.initStandardObjects(null, true);
                    ScriptableObject.defineClass(scope, A.class);
                    ScriptableObject.defineClass(scope, B.class);

                    cx.compileString("" +
                                    "new A().doSmth();" +
                                    "new B().a.doSmth();" +
                                    "", "", 1, null).exec(cx, scope);

            } catch (Exception e) {
                    e.printStackTrace();
            }
    }

} 

person Adrian    schedule 03.05.2011    source источник
comment
что произойдет, если вы измените тип возврата jsGet_a на ScriptableObject?   -  person ThomasRS    schedule 03.05.2011


Ответы (3)


Кажется, это работает:

  1. Сделал контекст и глобальную область приватными статическими переменными.
  2. Добавлен jsConstructor для класса A
  3. В jsConstructor для класса B создан объект javascript в коде.
  4. Использовал Context.toObject(a, this); с возвращаемым типом Scriptable в jsGet_a()
  5. Наконец, присвоил cx введенному контексту, а объем — глобальному объему.

    public class Test
    {
        private static Context cx;    
        private static ScriptableObject scope;
    
        public static class A extends ScriptableObject implements Scriptable {
    
            public A() {
            }
    
            public void jsConstructor() {
            }
    
            public String getClassName() {
                    return "A";
            }
    
            public void jsFunction_doSmth() {
                    System.out.println("I'm doing something");
            }
    
        }
    
        public static class B extends ScriptableObject implements Scriptable {
    
            private A a = new A();
    
            public B() {
            }
    
            public String getClassName() {
                return "B";
            }
    
            public void jsConstructor() {
            Scriptable scriptable = cx.newObject(scope, "A");
                this.put("a", this, scriptable);
            }
    
            public Scriptable jsGet_a() {
                return Context.toObject(a, this);
            }
    
        }
    
        public static void main(String[] args) {
            try {
                cx = Context.enter();
    
                scope = cx.initStandardObjects(null, true);
                ScriptableObject.defineClass(scope, A.class);
                ScriptableObject.defineClass(scope, B.class);
    
                cx.compileString("" +
                                "new A().doSmth();" +
                                "new B().a.doSmth();" +
                                "", "", 1, null).exec(cx, scope);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
person benjaminbytheway    schedule 09.08.2011
comment
После некоторых дополнительных исследований нет необходимости в методе jsGet_a() внутри класса B, когда вы вызываете this.put(a, this, scriptable) в jsConstructor B. Также нет необходимости в закрытой переменной a в классе Б либо. Так что, возможно, это не то, что вы ищете. - person benjaminbytheway; 10.08.2011

new B().a.doSmth();

не будет работать, так как a является частным.

new B().jsGet_a().jsFunction_doSmth();

вроде должно работать.

person Bala R    schedule 03.05.2011
comment
это код JS, который анализируется и выполняется через движок Rhino, а не код Java! - person Adrian; 03.05.2011
comment
да, но из javascript вы получаете доступ и создаете экземпляр java-кода; применяются те же правила, вы не можете получить доступ к закрытым переменным. - person Bala R; 03.05.2011

Согласно API, вы можете использовать метод

//  Get a named property from the object.
get(java.lang.String name, Scriptable start) 

в вашем java-объекте. Я предполагаю, что вы неправильно поняли преобразование отражения выше.

person ThomasRS    schedule 03.05.2011