VMware Cloud Community
StefanSchnell
Enthusiast
Enthusiast

Automatic Conversion of Java Data Types in JavaScript Data Types

The last few days I've been experimenting of using native Java data types in the JavaScript execution environment of vRealize Automation. Here, a behavior is visible that I cannot explain.

I tried to output all types of all Java primitive data types and the non-primitive data type string. But they were converted into JavaScript data types.

getSystemProperties5.jpg

If I tried the same with Rhino engine in the REPL mode, but here the data type object is always correctly returned.

getSystemProperties4.jpg

Also I tried the same approach directly in the vco-app-server container of the k8s cluster, with exactly the same result. On this way I can be quite sure that the type conversion is not dependent on the OS or the JDK.

StefanSchnell_0-1673676816166.png

 

 

var varBool = java.lang.Boolean.TRUE;
java.lang.System.out.println(typeof varBool + ": " + varBool);
var testBool = org.mozilla.javascript.Context.jsToJava(varBool, java.lang.Boolean);
java.lang.System.out.println(typeof testBool + ": " + testBool);
typeof java.lang.Boolean.TRUE;

 

 

If the data type object is returned, I can access to the corresponding methods. With the conversion into the JavaScript data types, I cannot use these methods.

This behavior can be reproduced with the following image:

getSystemProperties1.jpg

getSystemProperties2.jpg

In the first step, a variable of type Boolean is created and its type is output. In the second step I tried to convert it back to the Java data type Boolean, but with the same result as described above. In the third step I used a non-primitive data type, it delivers object but a method call occurs the error message, that the object can not convert into Property. A type conversion seems to have been made here as well.

How to prevent automatic conversion, aka force conversion, into JavaScript data types? Or the other way around, how can I use native Java data types in the JavaScript execution environment?

Thanks for hints and tips.

Addendum 03.05.2023

How to handle the primitive data types and strings can be read in the reply. Now there is still the question of how to handle the non-primitive data types.

Addendum 04.06.2023

StefanSchnell_0-1685871575682.png

 

 

// Begin----------------------------------------------------------------

try {

  var ints = java.lang.reflect.Array.newInstance(java.lang.Integer, 1);
  System.log(ints.constructor.name); //Array
  // System.log(ints.getClass()); // TypeError

  var int = java.lang.Integer(2147483647);
  // System.log(int.constructor.name); // TypeError
  System.log(int.getClass()); // class java.lang.Integer

} catch (exception) {
  System.log(exception);
}

// End------------------------------------------------------------------

 

 

Addendum 17.09.2023

It seems that the Dunes framework of Aria Automation changes native Java data types into in its opinion equivalent JavaScript data types automatically, Here an example:

StefanSchnell_0-1694923410718.png

 

 

/**
 * Hint: The Method getClass is inherited from the class java.lang.Object
 *       and it is available in both classes, because both extends the
 *       Object class.
 */

/**
 * The variable of the java.io.File class is automatically type casted
 * into the JavaScript data type File from the Dunes Framework.
 */
var javaIoFile = java.io.File.createTempFile("vco-", null);
System.log(javaIoFile.constructor.name);
// System.log(javaIoFile.getClass().getName());
// TypeError: Cannot find function getClass in object
// The method getClass is not available here, so this variable could not
// be from type java.io.File.

/**
 * The variable of the java.nio.file.Files class not type casted,
 * it is a Java data type.
 */
var javaNioFile = java.nio.file.Files.createTempFile("vco-", null);
// System.log(javaNioFile.constructor.name);
// TypeError: Cannot read property "name" from undefined
System.log(javaNioFile.getClass().getName());

 

 

The result of creating a temporary file using the java.io.File class is a JavaScript data type File from the Dunes Framework. If I do the same with the java.nio.file.Files class, then a native Java data type is returned. In the latter case, the native Java class methods can be used. This approach is not very sustainable, especially when using native Java data types in arrays. Because any array is automatically type casted into a JavaScript array by the Dunes framework. This makes the result unusable for further use in the native Java context.

StefanSchnell_1-1694924824155.png

Addendum 22.12.2023

List of native types, which are automatically type casted.

Native TypeConverted Type
java.lang.reflect.ArrayArray
java.io.FileFile
java.util.PropertiesProperties
java.util.HashMapProperties
java.net.URLURL
java.util.DateDate

 

automaticConversionOfJavaDataTypesInJavaScriptDataTypes.jpg


More interesting information at blog.stschnell.de

0 Kudos
1 Reply
StefanSchnell
Enthusiast
Enthusiast

In the context of my analyses here I read an answer of an interesting old post about inconsistent behaviour when accessing java.util.*-classes@bbonev wrotes: "When you try to invoke a method, the Rhino engine tries to call this method on this NativeObject ... It is a generic problem. If you create a new ArrayList, for example, the JS engine will map it to a native array and you won’t be able to call ArrayList’s methods." Here it is the other way around. Here my code to check the behaviour:

 

// Begin----------------------------------------------------------------

var javaLangBoolean = java.lang.Boolean.TRUE;
System.log("Boolean is " + typeof javaLangBoolean + " from " + javaLangBoolean.getClass());

var javaLangByte = java.lang.Byte.valueOf(127);
System.log("Byte is " + typeof javaLangByte + " from " + javaLangByte.getClass());

var javaLangShort = java.lang.Short.valueOf(32767);
System.log("Short is " + typeof javaLangShort + " from " + javaLangShort.getClass());

var javaLangInteger = java.lang.Integer.valueOf(2147483647);
System.log("Integer is " + typeof javaLangInteger + " from " + javaLangInteger.getClass());

var javaLangLong = java.lang.Long.valueOf(9223372036854775295);
System.log("Long is " + typeof javaLangLong + " from " + javaLangLong.getClass());

var javaLangFloat = java.lang.Float.valueOf(java.lang.Math.PI);
System.log("Float is " + typeof javaLangFloat + " from " + javaLangFloat.getClass());

var javaLangDouble = java.lang.Double.valueOf(java.lang.Math.PI);
System.log("Double is " + typeof javaLangDouble + " from " + javaLangDouble.getClass());

var javaLangString = java.lang.String("Hello World");
System.log("String is " + typeof javaLangString + " from " + javaLangString.getClass());

// End------------------------------------------------------------------

 

In the debugger, the above statements are confirmed.

vra_datatypes_debugger.jpg

This is exactly the opposite of the behavior we see in the vRA.

var_datatypes_script.jpg

The getClass method cannot be found, because java.lang.Boolean has been converted into the JavaScript data type boolean.

 

Addendum 03.05.2023

The behavior of Rhino Engine differs, when it used directly and when it used in Aria Automation. If the valueOf() method, which delivers an instance of a value, is omitted, the native Java data types are used, without force conversion. The following code works without any problems:

 

// Begin----------------------------------------------------------------

var javaLangBoolean = java.lang.Boolean(java.lang.Boolean.TRUE);
System.log("Boolean is " + typeof javaLangBoolean + " from " + javaLangBoolean.getClass());

var javaLangByte = java.lang.Byte(127);
System.log("Byte is " + typeof javaLangByte + " from " + javaLangByte.getClass());

var javaLangShort = java.lang.Short(32767);
System.log("Short is " + typeof javaLangShort + " from " + javaLangShort.getClass());

var javaLangInteger = java.lang.Integer(2147483647);
System.log("Integer is " + typeof javaLangInteger + " from " + javaLangInteger.getClass());

var javaLangLong = java.lang.Long(9223372036854775295);
System.log("Long is " + typeof javaLangLong + " from " + javaLangLong.getClass());

var javaLangFloat = java.lang.Float(java.lang.Math.PI);
System.log("Float is " + typeof javaLangFloat + " from " + javaLangFloat.getClass());

var javaLangDouble = java.lang.Double(java.lang.Math.PI);
System.log("Double is " + typeof javaLangDouble + " from " + javaLangDouble.getClass());

var javaLangString = java.lang.String("Hello World");
System.log("String is " + typeof javaLangString + " from " + javaLangString.getClass());

// End------------------------------------------------------------------

 

It delivers this result:

Boolean ist object from class java.lang.Boolean
Byte is object from class java.lang.Byte
Short is object from class java.lang.Short
Integer is object from class java.lang.Integer
Long is object from class java.lang.Long
Float is object from class java.lang.Float
Double is object from class java.lang.Double
String is object from class java.lang.String

On this way the native primitive data types and strings of Java can be used in the Rhino JavaScript engine in Aria Automation.
Note the different behavior of using Rhino Engine directly and in the context of Aria Automation.


More interesting information at blog.stschnell.de

0 Kudos