代码之家  ›  专栏  ›  技术社区  ›  andersonbd1

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

  •  3
  • andersonbd1  · 技术社区  · 7 年前

    $ jjs -v
    nashorn 1.8.0_45
    

    它阻碍了使用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位数字可以正常工作:

    $ echo 'var c = JSON.parse("{\"12\": \"a\", \"45\": \"b\"}"); print(c["12"])' | jjs; echo
    jjs> a
    

    $ echo 'var c = JSON.parse("{\"123\": \"a\", \"45\": \"b\"}"); print(c["123"])' | jjs; echo
    jjs> undefined
    

    3位数和字符串可以正常工作:

    $ echo 'var c = JSON.parse("{\"123\": \"a\", \"foo\": \"b\"}"); print(c["123"])' | jjs; echo
    jjs> a
    

    使用此版本,一切正常:

    $ jjs -v
    nashorn 1.8.0_121
    
    $ echo 'var c = JSON.parse("{\"123\": \"a\", \"456\": \"b\"}"); print(c["123"])' | jjs; echo
    jjs> a
    

    2 回复  |  直到 7 年前
        1
  •  7
  •   Hugues M.    7 年前

    下面是另一个不需要修改nashorn jar的解决方案:

    • nashorn.jar
    • 使用子第一个/父最后一个类装入器,例如 this one
    • 通过该类加载器加载发动机

    实现上述方法的示例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);
            }
        }
    }
    

    ### 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应用项目树:

    enter image description here

    在此之前,我也尝试过简单的捆绑 纳肖恩。罐子 WEB-INF/lib

    作为Java EE产品一部分的Servlet容器不应允许应用程序重写Java SE或Java EE平台类,例如 java.* javax.* 名称空间,Java SE或Java EE都不允许修改。

    " “,似乎如此 jdk.* 也属于这一类(无论如何,Tomcat似乎不包括Nashorn)。是的,带上你自己的类加载器

    包括您自己,但提供将文件添加到您分发的war中的说明(它只是一个zip文件),等等。

        2
  •  2
  •   user65839 user65839    7 年前

    maven-shade-plugin (取决于您的构建系统)以 relocate the packages META-INF/services/javax.script.ScriptEngineFactory NashornScriptEngineFactory.class 因此,它可以使用不同的脚本引擎名称。然后,您可以将其作为库添加到war文件中,然后使用创建脚本引擎的版本 new ScriptEngineManager().getEngineByName("my-nashorn"); 或者不管你给它起什么名字。

    its source code ,再次可能对其进行轻微修改,以赋予其自己的引擎名称。我不确定这是否会更容易,因为我没有尝试任何一种方法。

    1. 您需要修复的bug是在nashorn代码本身中修复的,而不是在底层JVM中实际修复的。
    2. 这样做是在许可协议范围内的。虽然看起来 source code is GPL 2 . 但我不是开源专家。

    我希望只更新服务器上的Java版本来修复已知的bug(以及 security patches !) 这将要容易得多,但如果你 要在特定的旧版本Java上运行特定代码的特定版本,您需要自己提供特定的代码。