Nashorn and AsciidoctorJs

Jim Laskey (Oracle) james.laskey at oracle.com
Tue Jul 29 18:36:17 UTC 2014


Alex,

It appears that Nashorn is converting the contents of the second argument (eval) to Script Mirrors when using getInterface.  This is causing some strange interactions later on.  The work around is to use invocable.invokeFunction("render", content, eval), (not using interfaces) until we can establish the why and what.  I'll file a bug when I get the details.

Cheers,

-- Jim

On Jul 29, 2014, at 10:38 AM, Alex Soto <asotobu at gmail.com> wrote:

> Yes it works when I run eval but not when I use the interface approach. Note that the eval code is the same as asciidoctorjava.js (which is used to declare methods of interface) , in both cases it should work but it only works when eval is called (calling the code directly).
> 
> 
> 2014-07-29 15:21 GMT+02:00 Jim Laskey (Oracle) <james.laskey at oracle.com>:
> I just remembered I'm running with 8u20 preview - likely has some affect.
> 
> -- Jim
> 
> 
> 
> On Jul 29, 2014, at 10:08 AM, Jim Laskey (Oracle) <james.laskey at oracle.com> wrote:
> 
> > [Just getting back]
> > Granted I tweaked the main to simplify the testing outside an IDE, but when I ran it it seems to work up to a point (asciidoctor.js:12234 timings.$start is undefined.):
> >
> >>> java -cp ../java nashorn.RenderDocumentWithNashorn
> > Working Directory = /Projects/asciidoctorjs/src/test/resources
> > <!DOCTYPE html>
> > <html lang="en">
> > <head>
> > <meta charset="UTF-8">
> > <!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
> > <meta name="viewport" content="width=device-width, initial-scale=1.0">
> > <meta name="generator" content="Asciidoctor 1.5.0-preview.8">
> > <title>Untitled</title>
> > <link rel="stylesheet" href="./asciidoctor.css">
> > </head>
> > <body class="article">
> > <div id="header">
> > </div>
> > <div id="content">
> > <div class="paragraph">
> > <p><strong>Hello World</strong></p>
> > </div>
> > </div>
> > <div id="footer">
> > <div id="footer-text">
> > Last updated 2014-07-29 09:56:41 ADT
> > </div>
> > </div>
> > </body>
> > </html>
> > *Hello World*
> > [object Object]
> > nashorn.AsciidoctorJs$$NashornJavaAdapter at 4a70d302
> > undefined
> > Exception in thread "main" <eval>:12235 TypeError: Cannot call undefined
> >       at jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:56)
> >       at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:212)
> >       at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:184)
> >       at jdk.nashorn.internal.runtime.ECMAErrors.typeError(ECMAErrors.java:171)
> >       at jdk.nashorn.internal.runtime.Undefined.lookupTypeError(Undefined.java:128)
> >       at jdk.nashorn.internal.runtime.Undefined.lookup(Undefined.java:100)
> >       at jdk.nashorn.internal.runtime.linker.NashornLinker.getGuardedInvocation(NashornLinker.java:98)
> >       at jdk.internal.dynalink.support.CompositeTypeBasedGuardingDynamicLinker.getGuardedInvocation(CompositeTypeBasedGuardingDynamicLinker.java:176)
> >       at jdk.internal.dynalink.support.CompositeGuardingDynamicLinker.getGuardedInvocation(CompositeGuardingDynamicLinker.java:124)
> >       at jdk.internal.dynalink.support.LinkerServicesImpl.getGuardedInvocation(LinkerServicesImpl.java:144)
> >       at jdk.internal.dynalink.DynamicLinker.relink(DynamicLinker.java:232)
> >       at jdk.nashorn.internal.scripts.Script$\^eval\_$32._L11888$_L11906$_L12223$_L12226(<eval>:12235)
> >       at jdk.nashorn.internal.scripts.Script$\^eval\_$34._L11888$_L11906$_L12223$_L12310(<eval>:12336)
> >       at jdk.nashorn.internal.scripts.Script$\^eval\_._L1(<eval>:2)
> >       at nashorn.AsciidoctorJs$$NashornJavaAdapter.render(Unknown Source)
> >       at nashorn.RenderDocumentWithNashorn.main(RenderDocumentWithNashorn.java:66)
> >
> > package nashorn;
> >
> > import java.io.*;
> > import java.util.HashMap;
> > import java.util.Map;
> > import java.util.Scanner;
> >
> > import javax.script.*;
> >
> > public class RenderDocumentWithNashorn {
> >    static void evalFile(String filename, ScriptEngine engine, SimpleScriptContext context) throws ScriptException, FileNotFoundException {
> >        engine.eval(new java.io.FileReader(filename), context);
> >    }
> >
> >    public static void main(String[] args) throws ScriptException, NoSuchMethodException, FileNotFoundException {
> >        System.out.println("Working Directory = " + System.getProperty("user.dir"));
> >
> >        ScriptEngineManager engineManager =
> >                new ScriptEngineManager();
> >        ScriptEngine engine =
> >                engineManager.getEngineByName("nashorn");
> >
> >
> >        SimpleScriptContext simpleScriptContext = new SimpleScriptContext();
> >        Bindings bindings = new SimpleBindings();
> >
> >        simpleScriptContext.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
> >
> >        try {
> >            evalFile("opal.js", engine, simpleScriptContext);
> >            evalFile("asciidoctor.js", engine, simpleScriptContext);
> >            evalFile("asciidoctor_extensions.js", engine, simpleScriptContext);
> >            evalFile("asciidoctorjava.js", engine, simpleScriptContext);
> >        } catch (ScriptException e) {
> >            throw new IllegalArgumentException(e);
> >        }
> >
> >        String content = "*Hello World*";
> >        Map<String, Object> options = new HashMap<>();
> >        options.put("header_footer", true);
> >
> >        simpleScriptContext.getBindings(ScriptContext.ENGINE_SCOPE).put("listOptions", options.keySet().toArray());
> >        simpleScriptContext.getBindings(ScriptContext.ENGINE_SCOPE).put("options", options);
> >        simpleScriptContext.getBindings(ScriptContext.ENGINE_SCOPE).put("content", content);
> >
> >
> >        Invocable invocable = (Invocable) engine;
> >
> >        Object eval = engine.eval("Opal.hash2(listOptions, options)", simpleScriptContext);
> >
> >        simpleScriptContext.getBindings(ScriptContext.ENGINE_SCOPE).put("hash2", eval);
> >
> >
> >
> >        engine.setContext(simpleScriptContext);
> >
> >        System.out.println(engine.eval("Opal.Asciidoctor.$render(content, hash2);", simpleScriptContext));
> >
> >        AsciidoctorJs asciidoctorJs =
> >                invocable.getInterface(
> >                        AsciidoctorJs.class);
> >        System.out.println(content);
> >        System.out.println(eval);
> >        System.out.println(asciidoctorJs);
> >        System.out.println(
> >                asciidoctorJs.render(content, eval));
> >
> >
> >    }
> >
> > }
> >
> >
> >
> >
> >
> > On Jul 26, 2014, at 9:02 AM, Alex Soto <asotobu at gmail.com> wrote:
> >
> >> Hi guys,
> >>
> >> currently I am working on integrating Asciidoctor to Java using Nashorn and
> >> Opal. Nowadays we have got an asciidoctor java running above JRuby.
> >>
> >> Apart from Asciidoctor java we also have an asciidoctorjs which is created
> >> using Opal (a gem to convert Ruby programs to JavaScript).
> >>
> >> So next step is to integrate this js to java using nashorn. But we are
> >> having one problem.
> >>
> >> I have created a project with a test so you can take a look as well:
> >> https://github.com/lordofthejars/asciidoctorjs
> >>
> >> The test is located at
> >> https://github.com/lordofthejars/asciidoctorjs/blob/master/src/test/java/rhino/RenderDocumentWithRhino.java
> >> (although it is called Rhino currently we are using Nashorn).
> >>
> >> If I create an script engine an I use the eval method everywhere it works
> >> perfectly but because I would like to use some more typesafe approach I
> >> decided to create an interface mirroring some asciidoctor operations so I
> >> call invocable.getInterface(AsciidoctorJs.class) to create the proxied
> >> instance and then I call defined methods.
> >>
> >> This interface mimics the js asciidoctorjava.js which internally calls
> >> asciidoctor.js operations. This is done because I only want some operations
> >> available from Java part, not the whole operations that asciidoctor.js
> >> offers.
> >>
> >> asciidoctorjava.js looks like:
> >>
> >> var render = function(content, optionsHash2) {
> >>   return Opal.Asciidoctor.$render(content, optionsHash2);
> >> };
> >>
> >> The problem is that when I run the test an exception is thrown notifying
> >> that Opal.Asciidoctor.$render is not found. If I change that line to:
> >>
> >> var render = function(content, optionsHash2) {
> >>   return "Hello World";
> >> };
> >>
> >> then it works so it seems that Nashorn don't load the asciidoctor.js but
> >> this is not exactly true because if I execute the same operation but using
> >> eval method it works.
> >>
> >> Probably I am missing something in the creation of proxied interface, but
> >> currently I cannot see what.
> >>
> >> Any idea on why this happens?
> >>
> >> Thank you so much for your help in advance.
> >>
> >> Alex.
> >>
> >> --
> >> +----------------------------------------------------------+
> >> Alex Soto Bueno - Computer Engineer
> >> www.lordofthejars.com
> >> +----------------------------------------------------------+
> >
> 
> 
> 
> 
> -- 
> +----------------------------------------------------------+
>   Alex Soto Bueno - Computer Engineer
>   www.lordofthejars.com
> +----------------------------------------------------------+



More information about the nashorn-dev mailing list