Доступ к статическим переменным Java из кода js в движке Nashorn

При попытке перенести старый код с движком Rhino на Nashorn в Java 8 у меня возникла проблема: доступ к статическим свойствам/методам из запущенного js-скрипта невозможен. Если я использую Rhino, он работает отлично. Я не знаю, что происходит с реализацией нового двигателя Nashorn.

import javax.script.*;

public class StaticVars {
    public static String myname = "John\n";
    public static void main(String[] args) {
        try{
            ScriptEngine engine;
            ScriptEngineManager manager = new ScriptEngineManager();
            engine=System.getProperty("java.version").startsWith("1.8")?            
                manager.getEngineByName("Nashorn") :    //j1.8_u51
                manager.getEngineByName("JavaScript");  //j1.7

            engine.put("staticvars", new StaticVars());
            engine.eval("print(staticvars.myname);");
            //print "John" if ran with java 7
            //print "undefined" if ran with java 8

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

person truongdao    schedule 20.09.2015    source источник


Ответы (2)


В Nashorn вы не можете получить доступ к статическим членам класса через экземпляры класса. Есть несколько способов добраться до статики. Вы можете получить объект типа, который действует и как конструктор, и как статическое пространство имен, так же, как имя типа действует в Java:

var StaticVars = Java.type("StaticVars"); // use your full package name if you have it
print(StaticVars.myname);

Или передайте объект java.lang.Class и используйте псевдосвойство .static для доступа к статике:

engine.put("StaticVarsClass", StaticVars.class);

с последующим:

var StaticVars = StaticVarsClass.static;
print(StaticVars.myname);

в сценарии. В общем случае .static является операцией, обратной .class:

var BitSet = Java.type("java.util.BitSet");
var bitSetClass = BitSet.class; // produces a java.lang.Class object, just like in Java
print(BitSet === bitSetClass.static); // prints true
var bitSet = new BitSet(); // type object creates a new bitset when used as a constructor
var thisWontWork = new bitSetClass(); // java.lang.Class can't be used as a constructor.

Как видите, мы различаем три понятия:

  • объекты класса среды выполнения, которые являются экземплярами java.lang.Class. Они не являются особыми, и вы можете использовать Class API только для них (.getSuperclass(), .getName() и т. д.).
  • сами экземпляры классов (обычные объекты, к которым вы можете получить доступ к членам экземпляра)
  • объекты типа, которые являются как пространствами имен для статических членов классов, которые они представляют, так и конструкторами. Ближайшим эквивалентом им в Java является имя класса, используемое в исходном коде; в JavaScript они являются реальными объектами.

На самом деле это создает наименьшую двусмысленность, поскольку все находится на своих местах и ​​наиболее точно соответствует идиомам платформы Java.

person Attila Szegedi    schedule 20.09.2015
comment
Оно работает! просто нужны некоторые изменения в коде. Кстати, эти методы не имеют обратной совместимости с Rhino. Спасибо! - person truongdao; 20.09.2015

Это не так, как должен работать js. Я думаю, что это ошибка дизайна в Nashorn. Предположим, у вас есть смешанная утилита, передающая vars из какой-то системы выполнения Java в сценарий js. Этот объект содержит один статический метод fmtNumber(someString) и один метод объекта jutil.getFormVar(someString). Пользователям не нужно знать, что Java обслуживает эту платформу. Вы просто говорите им, что jutil — это «системный хук», принадлежащий фреймворку foo. Как пользователю этого фреймворка мне все равно, статично оно или нет. Я js-разработчик, я не знаю насчет статики или нет. Я хочу написать что-нибудь очень быстро. Вот так выглядит код в rhino.

var x = jutil.getFormVar("x");
print(jutil.fmtNumber(x));

Теперь в насхорне я должен различать их. Хуже того, мне даже приходится обучать своих пользователей различать их и учить их терминам Java, которых они могут не знать, потому что это и есть уровень абстракции: самодостаточная система без необходимости знать лежащие в ее основе механизмы. Это различие приводит к большой когнитивной перегрузке, и вы не думали о других вариантах использования, кроме написания сценариев Java-разработчиками для себя, что они, вероятно, не будут делать, потому что уже знают хороший язык под названием Java. Вы думаете о своей реализации в качестве разработчика Java, вместо этого вам следует подумать, как вы могли бы использовать мощь платформы Java в фоновом режиме, скрывая все неприятные подробности от разработчиков JS. Что сказал бы веб-разработчик, если бы ему нужно было отличить статическую реализацию C++ в браузере?

person Christoph Sauer    schedule 04.02.2016