piumnl
12/21/2016 - 12:10 PM

a simple example for java script engine.

a simple example for java script engine.

package script;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;

import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.*;

/**
 * @author piumnl
 * @version 1.0.0
 * @since on 2016-12-14.
 */
public class ScriptDemo {

  private ScriptEngineManager manager;
  private ScriptEngine engine;

  /**
   * 测试之前的操作
   *
   * @since 2016/12/14
   */
  @Before
  public void before() {
    System.out.println("============正在初始化测试环境=============");

    manager = new ScriptEngineManager();
    engine = manager.getEngineByName("JavaScript");

    System.out.println("============成功初始化测试环境=============");
    System.out.println("===================测试开始===============");
  }

  /**
   * 测试getEngine()方法
   *
   * @since 2016/12/14
   */
  @Test
  public void test_getEngine() {
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");
    ScriptEngine extension = manager.getEngineByExtension("js");
    ScriptEngine mimeType = manager.getEngineByMimeType("text/javascript");
  }

  /**
   * 测试getScriptEngineFactory()方法
   *
   * @since 2016/12/14
   */
  @Test
  public void test_getScriptEngineFactory() {
    ScriptEngineManager manager = new ScriptEngineManager();
    List<ScriptEngineFactory> engineFactories = manager.getEngineFactories();

    for (ScriptEngineFactory engineFactory : engineFactories) {
      System.out.println("engineName:" + engineFactory.getEngineName());
      System.out.println("engineVersion:" + engineFactory.getEngineVersion());

      List<String> names = engineFactory.getNames();
      System.out.print("\tname:");
      for (String name : names) {
        System.out.print(name + ",");
      }
      System.out.println();

      List<String> mimeTypes = engineFactory.getMimeTypes();
      System.out.print("\tmimeType:");
      for (String mimeType : mimeTypes) {
        System.out.print(mimeType + ",");
      }
      System.out.println();

      List<String> extensions = engineFactory.getExtensions();
      System.out.print("\textension:");
      for (String extension : extensions) {
        System.out.print(extension + ",");
      }
      System.out.println();

      System.out.println("\tlanguageName:" + engineFactory.getLanguageName());
      System.out.println("\tlanguageVersion:" + engineFactory.getLanguageVersion());
      ScriptEngine scriptEngine = engineFactory.getScriptEngine();
    }
  }

  /**
   * 测试runScript()方法
   *
   * @since 2016/12/14
   */
  @Test
  public void test_runScript() throws ScriptException {
    // eval 直接运行 字符串 ,并返回该 表达式的结果
    engine.eval("var n = 10;");
    Object eval;
    eval = engine.eval("n == 10");
    Assert.assertTrue((Boolean) eval);

    // 运行 js 脚本
    try {
      String scriptFile = this.getClass().getResource("/").getPath() + "/simple.js";
      FileReader fileReader = new FileReader(new File(scriptFile));
      engine.eval(fileReader);
      Object t = engine.eval("t");
      Assert.assertEquals(201D, t);
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }

    // 向 引擎 绑定值
    engine.put("k", 1589);
    eval = engine.eval("k * 10");
    Assert.assertEquals(15890D, eval);

    // 从 引擎 中获取值,大多数脚本语言都可以访问 java 对象
    JButton button = new JButton();
    engine.put("b", button);
    engine.eval("b.text = 'OK'");
    Assert.assertEquals("OK", button.getText());

    // 全局作用域,对所有 引擎 可视
    manager.put("global", "This is the global scope");
    Assert.assertEquals("This is the global scope", engine.get("global"));

    // 可以将绑定的值放置在 Bindings 中,然后传递给 engine ,此时值就不存在于 engine 中。
    Bindings scope = engine.createBindings();
    scope.put("b", new JButton());
    engine.eval("b.name = 'H'", scope);
    eval = engine.eval("b.name", scope);
    Assert.assertEquals("H", eval);

    // 自定义 作用域
    // 定义类 实现 ScriptContext 接口,然后管理一个作用域集合,
    // 每个作用域都由一个整数标识,越小的数字越先被搜索。
    // 标准类库中提供了 SimpleScriptContext 类,但它只持有全局作用域和引擎作用域。
  }

  /**
   * 测试outputAndInput()方法
   *
   * @since 2016/12/14
   */
  @Test
  public void test_outputAndInput() throws ScriptException {
    StringWriter writer = new StringWriter();

    // 只能传 PrintWriter,否则会抛异常
    // 此处用 js 的print和println函数产生的输出会发送到writer中。
    engine.getContext().setWriter(new PrintWriter(writer, true));
    engine.eval("print('Hello')");
    Assert.assertEquals("Hello\r\n", writer.getBuffer().toString());

  }

  /**
   * 测试invokeFunction()方法
   *
   * @since 2016/12/14
   */
  @Test
  public void test_invokeFunction() throws ScriptException, NoSuchMethodException {
    // 调用脚本的函数,需要脚本引擎实现了 Invocable 接口
    engine.eval("function sum(a, b) { return a + b; }");

    if (engine instanceof Invocable) {
      Object sum = ((Invocable) engine).invokeFunction("sum", 10, 20);
      Assert.assertEquals(30D, sum);
      // 如果 脚本 是面向对象的,可以这样调用
      // ((Invocable) engine).invokeMethod(impliciParam, "aMethod", explicitParam1, explicitParam2);
      // 此处 的 impliciParam 对象是脚本语言编写的对象的一个代理,它必须是前一个脚本引擎调用的结果。
    }
  }

  /**
   * 测试implementInterface()方法
   *    js 实现 java 接口
   * @since 2016/12/14
   */
  @Test
  public void test_implementInterface() throws ScriptException {
    if (engine instanceof Invocable) {
      engine.eval("function greet(whom) { return 'Hello,' + whom + '!'; }");
      Greeter greeter = ((Invocable) engine).getInterface(Greeter.class);   // 注意 接口必须是 public
      greeter.greet("piumnl");
    }
  }

  /**
   * 测试implementInterfaceForOOP()方法
   * @since 2016/12/14
   */
  @Test
  public void test_implementInterfaceForOOP() throws ScriptException {
    if (engine instanceof Invocable) {
      engine.eval("function SimpleGreeter(salutation) {\n" +
        "  this.salutation = salutation\n" +
        "}\n" +
        "SimpleGreeter.prototype.greet = function (whom) {\n" +
        "  return this.salutation + ', ' + whom + '!';\n" +
        "}");
      Object bye = engine.eval("new SimpleGreeter('Goodbye')");
      Greeter greeter = ((Invocable) engine).getInterface(bye, Greeter.class);
      Assert.assertEquals("Goodbye, piumnl!", greeter.greet("piumnl"));
    }
  }

  /**
   * 测试compile()方法
   *    有时候对脚本编译可以加快运行速度
   * @since 2016/12/14
   * @throws FileNotFoundException
   */
  @Test
  public void test_compile() throws FileNotFoundException, ScriptException {
    String jsFile = this.getClass().getResource("/").getPath() + "/simple.js";
    FileReader fileReader = new FileReader(new File(jsFile));

    if (engine instanceof Compilable) {
      CompiledScript compile = ((Compilable) engine).compile(fileReader);
      if (compile != null) {
        compile.eval();
      } else {// 脚本引擎不支持编译
        engine.eval(fileReader);
      }
    }
  }

  public interface Greeter {
    String greet(String whom);
  }

}