使Javascript函数可用于Java代码 问题描述

使Javascript函数可用于Java代码 问题描述,java,javascript,Java,Javascript,一个有点做作的例子来说明我的问题。想象一下,我们有一些javascript函数库,这些函数库已经由大量前端开发人员每天维护和更新。具体来说,想象这样一个函数如下所示: function employeesForStore(store) { var dictionary = { "downtown": ["Joe", "Mary", "Steve"], "uptown": ["Jules", "Vincent", "Matt"], // an

一个有点做作的例子来说明我的问题。想象一下,我们有一些javascript函数库,这些函数库已经由大量前端开发人员每天维护和更新。具体来说,想象这样一个函数如下所示:

function employeesForStore(store) {
    var dictionary = {
        "downtown": ["Joe", "Mary", "Steve"],
        "uptown": ["Jules", "Vincent", "Matt"],
        // and so on for hundreds of locations
    };
    return dictionary[store];
}
注意:请忽略此函数实现的详细信息。实际函数可能比简单的JSON字典查找复杂得多,并且假设我们不知道有关js函数的任何实现细节。我们所知道的只是它接受一个字符串参数并返回字符串和字符串数组

现在我们想在Java代码中利用这个函数。也就是说,在Java代码中,我们希望“加载”这个函数,然后能够多次调用它,传递它
String
args并接收
String[]
ArrayList
结果

从搜索SO和google到目前为止,我了解到这将涉及使用:

  • javax.script.ScriptEngineManager
  • javax.script.ScriptEngine
  • 可能还有
    scriptEngine.getContext()
    ,用于将值传递到函数并接收结果
我对上面的细节有点模糊,尤其是因为我发现的大多数示例都涉及一次运行javascript代码,而不是让Java可以使用javascript函数

我想看看示例代码
  • 假设js函数位于文件“my_functions.js”中,将该文件加载到Java中,以便其所有函数都可以使用
  • 调用
    employeesForStore(“downtown”)
    并将其结果存储在本地java
    字符串[]
    列表
    中名为
    downtownResults
    的变量中
  • 与2相同,但调用
    employeesForStore(“uptown”)
    并将其存储在变量
    uptownResults
  • 您可以使用来在java中执行JS代码


    这涵盖了所要求的示例。

    创建一个接口,作为JavaScript代码的一部分

    下面是一个使用嵌入Oracle Java 1.7实现中的Rhino实现的示例:

    package demo;
    import java.io.*; import java.util.*;
    import java.util.concurrent.atomic.AtomicReference;
    import javax.script.*;
    
    public class StoreData {
      public static interface Stores {
        public String[] employees(String store);
      }
    
      public static Stores stores() throws IOException, ScriptException {
        ScriptEngineManager sem = new ScriptEngineManager();
        ScriptEngine engine = sem.getEngineByName("JavaScript");
        AtomicReference<Stores> ref = new AtomicReference<>();
        engine.put("ref", ref);
        String adapt = "ref.set("
            + "new Packages.demo.StoreData.Stores({employees:employeesForStore})"
            + ");";
        try (Reader myFns = new FileReader("my_functions.js")) { // TODO encoding
          engine.eval(myFns);
          engine.eval(adapt);
          return ref.get();
        }
      }
    
      public static void main(String[] args) throws IOException, ScriptException {
        List<String> employees = Arrays.asList(stores().employees("uptown"));
        System.out.println(employees);
      }
    }
    
    软件包演示;
    导入java.io.*;导入java.util.*;
    导入java.util.concurrent.AtomicReference;
    导入javax.script.*;
    公共类存储数据{
    公共静态接口存储{
    公共字符串[]员工(字符串存储);
    }
    public static Stores Stores()引发IOException、ScriptException{
    ScriptEngineManager sem=新ScriptEngineManager();
    ScriptEngine=sem.getEngineByName(“JavaScript”);
    AtomicReference ref=新的AtomicReference();
    发动机。放置(“参考”,参考);
    String adapt=“ref.set(”
    +“新包.demo.StoreData.Stores({employees:employeesForStore})”
    + ");";
    试试(Reader myFns=newfilereader(“my_functions.js”){//TODO编码
    发动机评估(myFns);
    发动机评估(自适应);
    返回ref.get();
    }
    }
    公共静态void main(字符串[]args)引发IOException、ScriptException{
    List employees=Arrays.asList(stores().employees(“住宅区”));
    系统输出打印LN(员工);
    }
    }
    
    通过指定接口,我们让Rhino将JavaScript类型强制为Java类型(String、String[]等)


    JRE规范规定了应该提供哪些脚本引擎,因此依赖外部引擎可能是明智的。我不知道你是否会改变这一点。

    在你的情况下,你只是在访问一个js对象,你可以将其序列化为JSON,然后用Java解析它。@moonwave99,忽略
    employeesForStore
    是如何实现的。我们不知道,这只是一个简单的例子。实际上,该函数可以在内部完全不同地实现,并且可能比简单的JSON字典查找复杂得多。(他们也建议使用犀牛)谢谢!你能解释一下
    adapt
    是怎么回事吗?它看起来像java代码,但是JS引擎正在评估它。是java还是js?似乎参数
    {employees:employeesForStore}
    以某种方式将java
    employees
    方法映射到js
    employeesForStore
    函数,这是否正确?到底是怎么回事?
    AtomicReference
    是负责映射还是其他什么+1已获取大量信息。
    存储。员工
    映射到
    员工存储
    。Rhino动态提供
    存储
    实现-请参阅。
    AtomicReference
    只是一种在创建实例后获取实例引用的方法(不是唯一的方法)。在这方面,
    AtomicReference
    类型没有什么特别之处。好吧,那么我们创建的JS脚本引擎能够交替使用java和JS代码吗?是的,Rhino通常会将JavaScript类型强制为java类型,例如,当它调用强类型java方法时。