Search code examples
javajava-8nashornscriptengine

Nashorn ScriptObjectMirror JS -> Java type conversion


When I access a JavaScript object's member variable using Nashorn ScriptObjectMirror.get(), the returned object's type seems to be determined at runtime. For example, if the value fits in a Java int, get() seems to return a Java Integer. If the value won't fit in an int, get() seems to return a Java Long, and so on.

Right now, I use instanceof to check the type and convert the value to a long.

Is there a more convenient way of getting a member's value without loss and without checking the type in Java? Perhaps Nashorn could always give me a Java Double, throwing an error in case the member's not numeric.

I can imagine this is a rather narrow case that probably shouldn't be handled by Nashorn...

Example:

package com.tangotangolima.test.nashorn_types;

import jdk.nashorn.api.scripting.ScriptObjectMirror;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.StringReader;

public class Main {

    public static void main(String[] args) throws ScriptException {
        final ScriptEngineManager mgr = new ScriptEngineManager();
        final ScriptEngine js = mgr.getEngineByName("nashorn");

        final String script = "" +
                "var p = 1;" +
                "var q = " + (Integer.MAX_VALUE + 1L) + ";" +
                "var r = {" +
                "s: 1," +
                "t: " + (Integer.MAX_VALUE + 1L) +
                " };";

        js.eval(new StringReader(script));

        say(js.get("p").getClass().getName());      // -> java.lang.Integer
        say(js.get("q").getClass().getName());      // -> java.lang.Long

        final ScriptObjectMirror r = (ScriptObjectMirror) js.get("r");

        say(r.get("s").getClass().getName());       // -> java.lang.Integer
        say(r.get("t").getClass().getName());       // -> java.lang.Long
    }

    static void say(String s) {
        System.out.println(s);
    }
}

Solution

  • Recommended approach is to check "instanceof java.lang.Number" from java code -- if you expect JavaScript "number" value. Once casted to Number, you can convert to int, long, double by calling methods such as intValue, longValue etc.