简体   繁体   English

我可以在战争中捆绑更新版本的Nashorn吗?

[英]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的解决方案:

  • bundle nashorn.jar (*) as a resource file in your war 捆绑nashorn.jar (*)作为战争中的资源文件
  • use a child-first/parent-last class loader such as this one 使用child-first / parent-last类加载器,例如这个
  • load the engine via this class loader 通过此类加载器加载引擎

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.* and javax.* 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: 这两种方法都假定:

  1. That the bug you need fixed is something that was fixed in the nashorn code itself, as opposed to something actually fixed in the underlying JVM. 您需要修复的错误是在nashorn代码本身中修复的内容,而不是在底层JVM中实际修复的内容。
  2. That doing so is within the licensing agreement. 这样做是在许可协议范围内。 I haven't looked into it, though it looks that the source code is GPL 2 . 我没有调查它,虽然它看起来源代码是GPL 2 But I'm no open source expert. 但我不是开源专家。

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.

相关问题 如何在Maven中组合WAR打包和OSGi包创建? - How can I combine WAR packaging and OSGi bundle creation in Maven? 如何让rJava在osx上使用更新版本的java? - How can I make rJava use the newer version of java on osx? 我可以在旧版本的Elasticsearch上使用新版本的Java高级别Rest客户端吗? - Can I use newer version of java high level rest client on an older version of elasticsearch? 我可以用较新的JDK用ant编译Java较旧版本的Java,以便在编译使用较新API的代码时生成输出吗? - Can i compile java for an older Java version with ant with a newer JDK so it generates output when it compiles code that uses the newer API? 是否可以使用比清单中指定的更新的捆绑版本而不更改当前捆绑? - Is it possible to use newer bundle version than specified in manifest without altering current bundle? 我无法重新安装Java:弹出新版本的Java发现消息 - I can't reinstalling java: newer version of java found message pops up 如何使用Webpack js文件从Nashorn调用方法? - How can I invoke a method from Nashorn with a webpack js file? 我可以从 Java 9 Nashorn 引擎运行 ECMAScript 6 - Can I run ECMAScript 6 from Java 9 Nashorn engine 如何确定Java WAR文件使用哪个servlet规范版本? - How can i determine which servlet spec version a java WAR file uses? 我们如何创建一个包含应用程序包的 war 文件? - How can we create a war file contaning a bundle of application?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM