【问题标题】:How do I get jjs --add-opens to work in java9?如何让 jjs --add-opens 在 java 9 中工作?
【发布时间】:2018-10-22 10:26:29
【问题描述】:

我一直在使用来自https://apimeister.com/2015/06/27/add-jar-to-the-classpath-at-runtime-in-jjs.html 的反射技术在运行时在 java 的 nashorn jjs 中加载类。

它在 java 8 中有效,但在 java 9 中却不行。我知道https://stackoverflow.com/a/41265267/5891192 中提到的推荐的命令行解决方法

根据https://stackoverflow.com/a/45970885/5891192,这种使用= 而不是标志和它的参数之间的空格的替代语法似乎也应该是有效的(因为通过-J--... 将jvm args 传递给jjs 的nashorn 方法是需要的)

有什么提示吗?


这行得通...(java 8)...

$ wget -q http://central.maven.org/maven2/org/apache/poi/poi/4.0.0/poi-4.0.0.jar
$ /usr/lib/jvm/java-1.8.0/bin/jjs -scripting loadit.js -- poi-4.0.0.jar
DONE

这不是... (java 9) ...

$ wget -q http://central.maven.org/maven2/org/apache/poi/poi/4.0.0/poi-4.0.0.jar
$ /usr/lib/jvm/java-9/bin/jjs -J--add-opens=java.base/java.net=ALL-UNNAMED -scripting loadit.js -- poi-4.0.0.jar

Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make protected void java.net.URLClassLoader.addURL(java.net.URL) accessible: module java.base does not "opens java.net" to module jdk.scripting.nashorn.scripts
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:337)...

这里是 loadit.js ...

// loadit.js 
function addUrlToClasspath(pth) {
  var s = java.lang.ClassLoader.getSystemClassLoader();
  var C = Java.type("java.lang.Class[]");
  var p = new C(1); p[0]  = java.net.URL.class;
  var m = java.net.URLClassLoader.class.getDeclaredMethod("addURL", p);
  var O = Java.type("java.lang.Object[]"); var a = new O(1); var f = new java.io.File(pth); m.setAccessible(true);
  var u = f.toURL(); a[0] = u; m.invoke(s, a);
}

addUrlToClasspath($ARG[0]);
print("DONE")

编辑:2018 年 10 月 23 日:更正了“这不是 (java 9)”示例命令行

【问题讨论】:

  • 系统类加载器不是 URLClassLoader,所以这个 hack 是行不通的。您是否考虑过创建自己的 URLClassLoader?
  • 这是涵盖此内容的 JDK 9 发行说明:oracle.com/technetwork/java/javase/…。没有支持在运行时扩展类路径的方法(只有工具代理可以这样做)。所以我认为你需要远离你正在做的事情,可能创建你自己的 URLClassLoader 实例并调用它来加载你正在寻找的类。
  • 哦,怀疑... System.out.println(ClassLoader.getSystemClassLoader() instanceof URLClassLoader); 怎么样?
  • 从 JDK 11 开始,您不需要为此使用 JavaScript,因为现在,java 本身可以启动简单的 Java 源代码文件。例如,请参阅dzone.com/articles/…。在这些“脚本”中,可以使用整个 Java API,包括类加载器。

标签: java reflection java-9 jjs


【解决方案1】:

正如我上面评论的,实际上有 3 个问题。

  1. 提出的问题 - 答案:a。没有帮助(见下一点) b.系统级 add-opens 命令行选项不会进入 jjs 使用的 Nashorn 引擎)
  2. 从 java9 开始,附加到系统类加载器方法无论如何都不起作用 - Java 9, compatability issue with ClassLoader.getSystemClassLoader
  3. 从 java-11 开始,jjs 本身被声明为弃用

但是,感谢 @Alan@Holger 和我的同事 @Philippe 的提示,我得到了我想要的解决方法。

  1. 您可以使用所需的 jars 创建自己的 URLClassLoader,并创建第二个 nashorn 引擎,传入该类加载器(例如来自 jjs 的命令行参数)。
  2. 添加另一个 hack 来为 script-within-a-script 实现所谓的 "here document"

...这是一个完整的例子:

// jjs -scripting ora2csv.js -- "select 'hi' from dual" jdbc:oracle:thin:@host:1521:XE user pass

function newJjsEngineWith (jars) {
  var ua = Java.type("java.net.URL[]"); var urls = new ua(jars.length);
  for(var i=0; i<jars.length; i++) {
    var u=new java.net.URL(new java.io.File(jars[i]).toURL());
    urls[i] = u;
  }
  var loader = new java.net.URLClassLoader(urls);
  java.lang.Thread.currentThread().setContextClassLoader(loader);
  var nsef = Java.type("jdk.nashorn.api.scripting.NashornScriptEngineFactory");
  var sa = Java.type("java.lang.String[]"); var args = new sa(2 + $ARG.length);
  args[0] = "-scripting"; args[1] = "--";
  for(var i=0;i<$ARG.length;i++) { args[i+2] = $ARG[i]; }
  return new nsef().getScriptEngine(args, loader);
}

var jjs = newJjsEngineWith(["ojdbc8.jar"]);

function hereDoc(f) { return f.toString().slice(14,-3); }

var code = hereDoc(function(){/*
var q = $ARG[0]; // select 'hello' from dual
var c = $ARG[1]; // jdbc:oracle:thin:@host:1521:XW
var u = $ARG[2]; // username
var p = $ARG[3]; // password
var conn = java.sql.DriverManager.getConnection(c, u, p);
var stmt = conn.createStatement(); rset = stmt.executeQuery(q);
var row=0;
while (rset.next()) {
  row++; var rowBuf = new java.lang.StringBuilder();
  var meta = rset.getMetaData();
  for(var col=0; col< meta.getColumnCount(); col++) {
    var cell = rset.getString(col+1);
    if (cell == null) { cell = ""; }
    rowBuf.append(cell.replaceAll(";",","));
    if (col < meta.getColumnCount()-1) { rowBuf.append(";"); }
  }
  print(rowBuf.toString());
}
stmt.close();
*/});

jjs.eval(code);

这适用于 java 8 到 java 11。

$ /usr/lib/jvm/java-1.8.0/bin/jjs -scripting ora2csv.js -- "select 'hi' from dual" jdbc:oracle:thin:@host:1521:XE user pass
hi
$ /usr/lib/jvm/java-9/bin/jjs -scripting ora2csv.js -- "select 'hi' from dual" jdbc:oracle:thin:@host:1521:XE user pass
hi
$ /usr/lib/jvm/java-10/bin/jjs -scripting ora2csv.js -- "select 'hi' from dual" jdbc:oracle:thin:@host:1521:XE user pass
hi
$ /usr/lib/jvm/java-11/bin/jjs -scripting ora2csv.js -- "select 'hi' from dual" jdbc:oracle:thin:@host:1521:XE user pass
Warning: The jjs tool is planned to be removed from a future JDK release
Warning: Nashorn engine is planned to be removed from a future JDK release
hi

我欢迎任何建议,以使其更简洁pukey

【讨论】:

    猜你喜欢
    • 2017-10-18
    • 1970-01-01
    • 2021-07-10
    • 2018-09-30
    • 2021-11-15
    • 2018-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多