-
Notifications
You must be signed in to change notification settings - Fork 0
Converting Script Values to Java
When values (including both primitives and objects) are passed back as parameters to Java methods, they are often converted. Nashorn supports a wide variety of automatic value conversions, that seek to incorporate both the flexibility of ECMAScript value conversion system as well as the rules of Java. In addition, in some situations explicit conversion operations are possible. We describe all below.
When a method on a Java object is invoked, the arguments are converted to the formal parameter types of the Java method using all allowed ECMAScript conversions. This can be surprising, as in general, conversions from string to number will succeed according to Standard's section 9.3 "ToNumber" and so on; string to boolean, number to boolean, Object to number, Object to string all work. In detail the supported conversions are as follows:
Java type | Conversion |
---|---|
boolean |
As per ECMAScript 9.2 ToBoolean conversion. Colloquially, as if you applied !! to the value. |
byte , short , int , float , long , double
|
As per ECMAScript 9.3 ToNumber conversion. Colloquially, as if you applied + to the value to obtain a JavaScript number and then if necessary used Java casting to convert to the target type. |
char |
If the value is null , (char)0 . If the value is a number between 0-65535 then (char)i , where i is the value of the number truncated to integer. Otherwise the value is converted to a string using ECMAScript 9.8 ToString conversion. If the result of the conversion is null , then (char)0 . Otherwise if the string length is not exactly 1, a TypeError is thrown. Otherwise, the first character of the string is returned. |
String , CharSequence
|
null is passed as-is, otherwise ECMAScript 9.8 ToString conversion is used. |
Number |
null is passed as-is, but the concrete type might be either Integer or Double . |
Character |
as char , except null is passed as-is and not converted to (char)0 . |
Byte , Short , Int , Float , Long , Double
|
null is passed as-is, otherwise as for the primitive types. Undefined values are converted to either Nan for floats and doubles or null for integer types. |
lambda types | If the type is a Java lambda type (an interface or abstract class with a single method), you can pass in an ECMAScript function and Nashorn will do the right thing, and create an adapter for the lambda type. Nashorn is even more versatile than Java though, you can pass a function for a type that has multiple abstract methods, but they all share the same name (the name is overloaded.) In that case, the passed function will be used as the implementation for all the overloads and must analyze the number and types of its parameters to decide which overload was invoked. |
Map |
null is passed as-is. Any script object will be passed as-is, as they all implement the Map interface with string keys. This is true of script arrays too. Primitive types can not be passed (they are not run automatically through ECMAScript ToObject conversion.) |
List , Collection , Queue , Dequeue
|
null is passed as-is. For native script arrays, an adapter is returned that exposes the array. Note that with ECMAScript arrays, push and pop operate at the end of the array, while in Java Deque they operate on the front of the queue and as such the Java dequeue push and pop operations will translate to unshift and shift script operations respectively, while Java addLast and removeLast will translate to push and pop . Primitive values and objects that are not arrays can not be passed. It is possible to enforce converting other array-like objects to lists and queues with explicit call to Java.to , see later. |
Java array types | Script arrays are converted to Java arrays using per-component conversions. If the target Java array type is multidimensional, components are recursively converted, so it will properly convert arrays-of-arrays etc. Objects that are not native script arrays can not be passed. It is possible to enforce converting other array-like objects to Java arrays with explicit call to Java.to , see later. |
Object |
if the Java parameter type is just Object , values are passed as they are. JavaScript primitive values are passed as Boolean (for booleans), Number (for numbers), and CharSequence (for strings). Strings are not necessarily a Java String but they are always a CharSequence . Numbers will usually be Integer or Double . Script objects will be passed as object implementing both Nashorn's JSObject interface and also the Map interface. This is true of script arrays too –- if you need arrays to implement List instead, you'll need to use Java.asJSONCompatible explicit conversion method found in the built-in Java global object. |
The built-in Java object contains two methods useful for explicit specialized conversions to Java types: Java.asJSONCompatible
and Java.to
.
This method is useful if you need to pass a script array (or an object graph containing script arrays recursively) such that array adapters should expose List
interface instead of the Map
interface that is by default exposed by all script objects to Java. The name of the method stems from the fact that various Java JSON libraries typically have this expectation. Unfortunately, it is also impossible for a single Java class to implement both Map
and List
interfaces, hence we are providing the developer here with a choice of how to represent script arrays in Java.
While Nashorn automatically converts native script arrays (those of script class Array
) to either Java arrays or to Collection
, List
, Queue
, and Deque
interface, it won't do that for other objects that might still be "array-like". A script object is array-like if it has a length
property and push
, pop
, shift
, unshift
, and splice
methods, with the expectation that all of them have same behaviors as the native script arrays. Using Java.to
you can explicitly convert such array-like objects to Java arrays or collections:
var someArrayLike = ...
javaObj.methodExpectingIntArray(Java.to(someArrayLike, Java.type("int[]"))
If converting to lists or queues, the adapter will call splice
to add or remove elements in the middle of the list, push
, and unshift
to add elements to the start and end of the list, and pop
and shift
to remove elements from the start and end of the list.
Note that with ECMAScript arrays, push
and pop
operate at the end of the array, while in Java Deque
they operate on the front of the queue and as such calls to the Java dequeue addFirst
/push
and removeFirst
/pop
methods will translate to unshift
and shift
script methods respectively, while Java addLast
and removeLast
will translate to script push
and pop
.