graaljs icon indicating copy to clipboard operation
graaljs copied to clipboard

InputStream#read fails to work with

Open Melab opened this issue 3 years ago • 1 comments

As an example, consider a file /tmp/file.txt whose contents are abc and run this code in the GraalVM JavaScript launcher in JVM mode:

let Path = Java.type("java.nio.file.Path");
let Files = Java.type("java.nio.file.Files");
let bytes = [0, 0, 0];
Files.newInputStream(Path.of("/tmp/file.txt")).read(bytes);

The contents of bytes remains all zeros and it was supposed to look like [97, 98, 99] at the end. This is especially strange because InputStream#readAllBytes returns an array and its return type in the Java documentation is byte[]—exactly the same as the type of the first parameter of InputStream#read. This behavior is inconsistent and hobbles efforts to build JavaScript that uses Java to read from files.

Melab avatar Feb 28 '22 23:02 Melab

When you pass a JavaScript array as an argument to InputStream.read(byte[]) then a Java array (of type byte[]) is created, the content of the JavaScript array is copied into this Java array and the method is invoked with the Java array passed as an argument. So, the bytes are written into the Java array, not into the JavaScript array. That's why you see the original content of the JavaScript array. It is not possible to create Java array that would delegate its reads and writes to the original JavaScript array. The only possibility to make your test-case working would be some explicit comparison and synchronization of the arrays when the Java method returns. While this may seem natural in this case, it would be really problematic in a general case. So, I don't think that this will ever get implemented. Hence, the best I can suggest you is to use byte[] array in this case, i.e., replace

let bytes = [0, 0, 0];

by

let byteArray = Java.type("byte[]");
let bytes = new byteArray(3);

This is especially strange because InputStream#readAllBytes returns an array and its return type in the Java documentation is byte[]—exactly the same as the type of the first parameter of InputStream#read.

This case is much simple. You invoke Java method that creates and returns byte[]. When this Java array is passed to JavaScript then you just see the content of this Java array. There is no complex interoperability between Java and JavaScript arrays needed.

iamstolis avatar Mar 01 '22 07:03 iamstolis