[英]Can I bundle a newer version of Nashorn in a war?
Unless I'm missing something here, this version of Nashorn appears to have some bugs: 除非我在这里遗漏了一些东西,否则这个版本的Nashorn似乎有一些错误:
$ jjs -v
nashorn 1.8.0_45
it chokes on using multiple integrals of 3 digits or more as property keys: 它使用3位或更多位的多个积分作为属性键扼流:
$ echo 'var c = JSON.parse("{\"123\": \"a\", \"456\": \"b\"}"); print(c["123"])' | jjs; echo
jjs> java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 7
2 digits works fine: 2位数工作正常:
$ echo 'var c = JSON.parse("{\"12\": \"a\", \"45\": \"b\"}"); print(c["12"])' | jjs; echo
jjs> a
3 digits and 2 digits gives a different error: 3位数字和2位数字给出了不同的错误:
$ echo 'var c = JSON.parse("{\"123\": \"a\", \"45\": \"b\"}"); print(c["123"])' | jjs; echo
jjs> undefined
a 3 digit and a string work fine: 3位数字和字符串工作正常:
$ echo 'var c = JSON.parse("{\"123\": \"a\", \"foo\": \"b\"}"); print(c["123"])' | jjs; echo
jjs> a
it all works fine using this version: 使用这个版本一切正常:
$ jjs -v
nashorn 1.8.0_121
$ echo 'var c = JSON.parse("{\"123\": \"a\", \"456\": \"b\"}"); print(c["123"])' | jjs; echo
jjs> a
Anyway, the above snippets are just a way to demonstrate an issue I'm having in my webapp. 无论如何,上面的代码片段只是一种展示我在webapp中遇到的问题的方法。 My question is - is there a way to bundle this newer version of nashorn in my webapp so that I don't need to request a java upgrade on the server?
我的问题是 - 有没有办法在我的webapp中捆绑这个较新版本的nashorn,这样我就不需要在服务器上请求java升级了?
Here is another solution that does not require modifying the nashorn jar: 这是另一个不需要修改nashorn jar的解决方案:
nashorn.jar
(*) as a resource file in your war nashorn.jar
(*)作为战争中的资源文件 Example servlet that implements the approach above, and then tries to evaluate your script with both the JRE's Nashorn, and the bundled Nashorn: 实现上述方法的示例servlet,然后尝试使用JRE的Nashorn和捆绑的Nashorn评估您的脚本:
@WebServlet("/nashorn")
public class NashornDemoServlet extends HttpServlet {
private static final ClassLoader CL;
static {
// In my case nashorn.jar is under WEB-INF/classes (resources root)
URL nashornURL = NashornDemoServlet.class.getClassLoader().getResource("nashorn.jar");
CL = new ParentLastURLClassLoader(Collections.singletonList(nashornURL));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
String script = "var c = JSON.parse(\"{\\\"123\\\": \\\"a\\\", \\\"456\\\": \\\"b\\\"}\"); c[\"123\"]";
ScriptEngine nashorn = new ScriptEngineManager(getClass().getClassLoader()).getEngineByName("nashorn");
try {
Object result = nashorn.eval(script);
out.println("### JRE Nashorn result: " + result);
} catch (Exception e) {
out.println("### JRE Nashorn failed!");
e.printStackTrace(out);
}
try {
Class<?> clazz = CL.loadClass("jdk.nashorn.api.scripting.NashornScriptEngineFactory");
Object factory = clazz.newInstance();
ScriptEngine engine = (ScriptEngine) clazz.getMethod("getScriptEngine").invoke(factory);
Object result = engine.eval(script);
out.println("\n### Bundled Nashorn result: " + result);
} catch (Exception e) {
out.println("### Bundled Nashorn failed!");
e.printStackTrace(out);
}
}
}
Result using tomcat 8, on JRE 8u45: 在JRE 8u45上使用tomcat 8的结果:
### JRE Nashorn failed!
java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 7
at java.util.Arrays.rangeCheck(Arrays.java:120)
at java.util.Arrays.fill(Arrays.java:2868)
at jdk.nashorn.internal.runtime.BitVector.setRange(BitVector.java:273)
...
at java.lang.Thread.run(Thread.java:745)
### Bundled Nashorn result: a
Web app project tree: Web应用程序项目树:
Before that I also tried simply bundling nashorn.jar
under WEB-INF/lib
without custom class-loader trick (hoping the usual child-first class loader of servlet container would be enough), but that did not work. 在此之前,我还尝试在
WEB-INF/lib
下简单地捆绑nashorn.jar
而不使用自定义类加载器技巧(希望servlet容器的通常的子级优先级加载器就足够了),但这不起作用。 I suppose this is because Tomcat follows this rule from the servlet spec: 我想这是因为Tomcat遵循servlet规范中的这条规则:
Servlet containers that are part of a Java EE product should not allow the application to override Java SE or Java EE platform classes, such as those in
java.*
andjavax.*
namespaces, that either Java SE or Java EE do not allow to be modified.作为Java EE产品一部分的Servlet容器不应允许应用程序覆盖Java SE或Java EE平台类,例如
java.*
和javax.*
命名空间中的那些,Java SE或Java EE不允许这些类改性。
" Such as ", so it seems jdk.*
also falls in that category (in any case, Tomcat does seem to exclude Nashorn). “ 比如 ”,所以似乎
jdk.*
也属于那个类别(无论如何,Tomcat似乎确实排除了Nashorn)。 So yeah, bring your own ClassLoader 😉 所以是的,带上你自己的ClassLoader😉
(*) Make sure you can legally do that. (*)确保你可以合法地做到这一点。 Maybe consider using a jar from an OpenJDK build, not copied from an Oracle Java installation directory.
也许考虑使用OpenJDK构建中的jar,而不是从Oracle Java安装目录中复制。 Maybe consider not including yourself it but providing instructions to add the file to the war you distribute (it's just a zip file), etc.
也许考虑不包括你自己,但提供说明将文件添加到你分发的战争(它只是一个zip文件),等等。
In principle, I would expect that you should be able to take the nashorn.jar from the newer JRE's \\lib\\ext folder and run it through something like a maven-shade-plugin (depending on your build system) to relocate the packages to a different name (so as not to conflict with the existing ones in the underlying JVM you want to want it on). 原则上,我希望您能够从较新的JRE的\\ lib \\ ext文件夹中获取nashorn.jar并通过类似maven-shade-plugin (取决于您的构建系统)的方式运行它以将包重新定位到一个不同的名称(以免与您希望它所在的底层JVM中的现有名称冲突)。 You'd probably also want to change the
META-INF/services/javax.script.ScriptEngineFactory
in the new jar that you are making accordingly, and also change the values in the NashornScriptEngineFactory.class
so that it has a different scripting engine name to use. 您可能还想在相应的新jar中更改
META-INF/services/javax.script.ScriptEngineFactory
,还要更改NashornScriptEngineFactory.class
的值,以便它具有不同的脚本引擎名称。采用。 Then you could add that as a library to your war file, and then create your version of the scripting engine using new ScriptEngineManager().getEngineByName("my-nashorn");
然后你可以将它作为库添加到war文件中,然后使用
new ScriptEngineManager().getEngineByName("my-nashorn");
创建脚本引擎的版本new ScriptEngineManager().getEngineByName("my-nashorn");
or whatever name you gave to it. 或者你给它的任何名字。
Alternatively, you might try to compile Nashorn yourself from its source code , again perhaps modifying it slightly to give it your own engine name. 或者,您可以尝试从源代码自己编译Nashorn,也可以稍微修改它以给它自己的引擎名称。 I'm not sure whether or not that'd be easier, since I haven't tried either approach.
我不确定这是否更容易,因为我没有尝试过任何一种方法。
Both of those approaches assume: 这两种方法都假定:
I would expect that just updating the version of Java on the server to fix known bugs (and security patches !) would be have to be significantly easier, but if you need to run some specific version of some specific code on that specific old buggy edition of Java, you need to provide that specific code yourself somehow. 我希望只是更新服务器上的Java版本来修复已知错误(以及安全补丁 !)必须要简单得多,但如果你需要在特定的旧版bug上运行某些特定代码的特定版本对于Java,您需要以某种方式自己提供该特定代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.