Surprising difference between /usr/bin/jjs and .getEngineByName("JavaScript")

Sundararajan Athijegannathan sundararajan.athijegannathan at oracle.com
Wed Dec 21 12:43:24 UTC 2016


No.  We do not discourage javax.script API. javax.script is the main 
API. Nashorn specific extension API is in jdk.nashorn.api.* packages.

This undefined to null translation was already discussed -> 
http://mail.openjdk.java.net/pipermail/nashorn-dev/2016-December/006707.html

javax.script API - which is scripting language independent API - 
translates undefined to null. Nashorn specific API 
jdk.nashorn.api.scripting.* does not.

jjs, which is a nashorn specific shell, does not translate undefined.

-Sundar

On 21/12/16, 5:49 PM, Esben Andreasen wrote:
> Hi Hannes
>
> Thank you for that explanation.
>
> A follow-up, if allowed:
> I understand the motivation for eliminating `undefined`, but I would really
> like a way that I could avoid that elimination. Is that a discouraged use
> of the API?
>
> Implementation-wise:
> I see that  `ScriptObjectMirror.translateUndefined` does the conversion
> from JavaScript `undefined` to Java `null`.
> I assume I could make a lightly edited copy of NashornScriptEngine.java
> that omits the call to `translateUndefined` to get the effect I want. Or is
> there a more elegant solution somewhere?
>
>
> On Wed, Dec 21, 2016 at 11:40 AM Hannes Wallnöfer<
> hannes.wallnoefer at oracle.com>  wrote:
>
>> Hi Esben,
>>
>> The reason you get null instead of undefined with the embedded script
>> engine is that undefined is a language specific artefact that can’t be
>> represented in Java. The script API translates undefined to null when it is
>> returned by a script.
>>
>> Hannes
>>
>>
>>> Am 21.12.2016<21%2012%2020%2016>  um 11:09 schrieb Esben Andreasen<
>> esben at esbena.dk>:
>>> Hi
>>>
>>> I am not sure if this is a bug or a problem with my setup.
>>> I observe a surprising difference between the "external" (jjs) and the
>>> "internal" (new ScriptEngineManager().getEngineByName("JavaScript"))
>>> Nashorn when evaluating a regular expression method. The two Nashorns
>> seems
>>> to be the same, but I am not sure how to check.
>>>
>>> Consider the following two interactions with Nashorn (output manually
>>> transformed to have the same form):
>>>
>>> ```
>>> Evaluating in internal Nashorn (new
>>> ScriptEngineManager().getEngineByName("JavaScript")):
>>>> java.lang.System.getProperty('java.version')
>>> 1.8.0_111
>>>> /(x)(y)?/.exec('x')[2]
>>> null
>>>
>>> Evaluating in external Nashorn (/usr/bin/jjs):
>>>> java.lang.System.getProperty('java.version')
>>> 1.8.0_111
>>>> /(x)(y)?/.exec('x')[2]
>>> undefined
>>> ```
>>>
>>> Observations:
>>> 1. the Java version for both interactions is the same. I *think* this
>> means
>>> that the version of Nashorn is the same as well, but I am not sure.
>>> 2. the two interactions disagree on `null/undefined` as the second entry
>> of
>>> the result array. The `undefined` value is the correct one according to
>>> other JavaScript engines.
>>>
>>> Questions:
>>> 1. Are the two Nashorns of the same version?
>>> 2. Is the null/undefined discrepancy a bug?
>>>
>>> ---------------------------------------
>>>
>>> Additional content:
>>>
>>> The interactions with the Nashorns where performed with the following
>> Java
>>> class:
>>>
>>> ```
>>> import javax.script.ScriptEngine;
>>> import javax.script.ScriptEngineManager;
>>> import javax.script.ScriptException;
>>> import java.io.BufferedReader;
>>> import java.io.IOException;
>>> import java.io.InputStreamReader;
>>> import java.nio.file.Files;
>>> import java.nio.file.Path;
>>> import java.util.ArrayList;
>>> import java.util.Arrays;
>>> import java.util.List;
>>> import java.util.function.Function;
>>>
>>> public class NashornTest {
>>>
>>> public static void main(String[] args) throws ScriptException,
>> IOException,
>>> InterruptedException {
>>> String javaVersionScript =
>> "java.lang.System.getProperty('java.version')";
>>> String execScript = "/(x)(y)?/.exec('x')[2]";
>>>
>>> showEvaluation("Evaluating in internal Nashorn (new
>>> ScriptEngineManager().getEngineByName(\"JavaScript\")):",
>>> NashornTest::evaluateInternally, javaVersionScript, execScript);
>>> System.out.println();
>>> showEvaluation("Evaluating in external Nashorn (/usr/bin/jjs):",
>>> NashornTest::evaluateExternally, javaVersionScript, execScript);
>>> }
>>>
>>> private static void showEvaluation(String title, Function<String, String>
>>> evaluator, String... scripts) {
>>> System.out.println(title);
>>> for (String script : scripts) {
>>> System.out.println("\t>  " + script);
>>> System.out.println("\t" + evaluator.apply(script));
>>> }
>>> }
>>>
>>> private static String evaluateInternally(String script) {
>>> ScriptEngine engine = new
>>> ScriptEngineManager().getEngineByName("JavaScript");
>>> try {
>>> return engine.eval(script) + "";
>>> } catch (ScriptException e) {
>>> throw new RuntimeException(e);
>>> }
>>> }
>>>
>>> private static String evaluateExternally(String script) {
>>> Path scriptFile = null;
>>> try {
>>> scriptFile = Files.createTempFile("script", ".js");
>>> Files.write(scriptFile, Arrays.asList(String.format("print(%s);",
>> script)));
>>> Process process = Runtime.getRuntime().exec(new String[]{"/usr/bin/jjs",
>>> scriptFile.toAbsolutePath().toString()});
>>> BufferedReader stdInput = new BufferedReader(new
>>> InputStreamReader(process.getInputStream()));
>>> List<String>  lines = new ArrayList<>();
>>> String line;
>>> while ((line = stdInput.readLine()) != null) {
>>> lines.add(line);
>>> }
>>> return String.join("\n", lines);
>>> } catch (IOException e) {
>>> throw new RuntimeException(e);
>>> }
>>> }
>>> }
>>>
>>> ```
>>


More information about the nashorn-dev mailing list