2014-11-25 2 views
2

В Java 7 (1,7), я мог бы получить доступ к методу Java с JavaScript, запустив это:Nashorn доступ нестатического метод Java

ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript"); 
jse.eval("importClass(net.apocalypselabs.symat.Functions);"); 
jse.eval("SyMAT_Functions = new net.apocalypselabs.symat.Functions();"); 

String input = "notify(\"Foo\");"; // This is user input 

jse.eval("with(SyMAT_Functions){ "+input+" }"); 

Что бы запустить функцию Notify() из класса функций Java:

public class Functions { 
    private Object someObjectThatCannotBeStatic; 
    public void notify(Object message) { 
     JOptionPane.showMessageDialog(null, message.toString()); 
    } 
    /* Lots more functions in here, several working with the same non-static variable */ 
} 

Как получить доступ к классу функций в Java 1.8 с помощью механизма Nashorn? Моя цель - запустить другой код для первого фрагмента, если у пользователя есть Java 1.8, в то же время позволяя пользователям с 1.7 использовать приложение.

Я пробовал http://www.doublecloud.org/2014/04/java-8-new-features-nashorn-javascript-engine/, https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/api.html и How to instantiate a Java class in JavaScript using Nashorn? без везения. Ни один из них, похоже, не позволяет мне делать то же самое, что и Java 1.7, вместо этого предполагая, что я хочу получить доступ к статическим функциям и объектам.

Самая распространенная ошибка, я получаю:

Я начинаю с ...

ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript"); 
jse.eval("var SyMAT_Functions;with (new JavaImporter(Packages.net.apocalypselabs.symat)) {" 
        + "SyMAT_Functions = new Functions();}"); 

... потом ...

jse.eval("with(SyMAT_Functions){ "+input+" }"); 

... выплевывает ...

TypeError: Cannot apply "with" to non script object in <eval> at line number 1 
+0

Что не работает в Java 8? Есть ли сообщение об ошибке или трассировка стека, которую вы можете включить? –

+0

@WilliamPrice Ошибки изменяются в зависимости от метода, который я пытаюсь использовать. Моя проблема в том, что я не могу получить доступ к нестационарным методам в Java 8, как бы я ни старался. –

+0

@WilliamPrice Хорошо, я отредактировал одну из моих попыток и то, что меня достало. Я пробовал все разные методы, приведенные в этих ссылках, если я правильно помню, все они дали мне, что «TypeError» после того, как они возились с ними. –

ответ

2

Я смог воспроизвести. Прежде всего, Nashorn не пытается затруднить использование объектов Java (не статических или других) в целом. Я использовал его в других проектах и ​​не имел серьезных проблем с преобразованием Rhino в Java 7 за рамки того, что описано в migration guide. Однако здесь проблема связана с использованием with statement, который «не рекомендуется», и даже запрещен в режиме strict ECMAScript 5.1, как в соответствии с MDN.

Между тем, я нашел a thread on the Nashorn-dev mailing list, обсуждая аналогичный случай. Соответствующая часть ответа была:

Насхорн позволяет объекты только скрипт (то есть объекты, созданные конструктором JS или JS объект буквального выражения) в виде выражения возможности для «с» заявлением. Произвольные объекты. , , не может использоваться как выражение «scope» для 'with'.

В jdk9 была добавлена ​​поддержка для поддержки объектов сценария зеркало другое сценарии или другие глобальные переменные (которые являются экземплярами ScriptObjectMirror).

Это не самое элегантное решение, но без использования JDK 9, я был в состоянии получить целевое использование with функционировать путем записи прокси-объект внутри Javascript чтобы отразить public API класса Java :

package com.example; 

import javax.script.*; 

public class StackOverflow27120811 
{ 
    public static void main(String... args) throws Exception { 
     ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript"); 
     jse.eval(
      "var real = new Packages.com.example.StackOverflow27120811(); " + 
      "var proxy = { doSomething: function(str) { return real.doSomething(str); } }; " 
     ); 
     jse.eval("with (proxy) { doSomething(\"hello, world\"); } "); 
    } 

    public void doSomething(String foo) { 
     System.out.println(foo); 
    } 
} 

Attila Szegedi отметил нестандартное Насхорн Object.bindProperties функцию . Хотя нельзя ожидать, что он будет работать ни с чем, кроме двигателя Nashorn, он делает устраняет сложность повторного объявления всего публичного API внутри объекта proxy.Используя такой подход, первый jse.eval(...) вызова может быть заменен:

jse.eval(
    "var real = new Packages.com.example.StackOverflow27120811(); " + 
    "var proxy = { }; " + 
    "Object.bindProperties(proxy, real); " // Nashorn-only feature 
); 
+1

Nashorn также предоставляет нестандартную функцию конструктора 'Object' с именем' bindProperties'. При этом вы можете добавить все свойства одного объекта в качестве связанных свойств к другому объекту; что в основном дает вам автоматическое проксирование того типа, который вы сделали (вы также можете создавать композиты, связывая свойства нескольких объектов, но я отвлекаюсь). Вы можете использовать 'var proxy = Object.bindProperties ({}, real);' в приведенном выше примере. Я знаю, было бы лучше, если бы мы продлили с заявлением, чтобы он мог принять POJO ... это не сложное техническое ограничение, просто то, что мы пока не смогли разработать. –

Смежные вопросы