google / j2cl

Java to Closure JavaScript transpiler
Apache License 2.0
1.23k stars 144 forks source link

byte[] does not work as type parameter when return value is Uint8array #145

Closed rbsdc closed 2 years ago

rbsdc commented 2 years ago

Describe the bug When byte[] is used as type parameter and an Uint8Array is used as return value in JavaScript, then an error is thrown. If byte[] is used directly, it works fine with Uint8Array. Mentioned in a comment here: https://github.com/google/j2cl/issues/144.

To Reproduce The following code does work when transpiled to JavaScript:

interface FileReader {
  byte[] readRange(int offset, int length);
}
class FileTest {
  public void doSomething(FileReader reader) {
    byte[] bytes = reader.readRange(0, 10);
  }
}

In Javascript:

class FileReader {
   readRange(offset, length) {
      return new Uint8Array([1, 2]); 
  }
 let fileTest = new FileTest();
 fileTest.doSomething(new FileReader()) // works
}

The following does not work:

@JsType
public interface Thenable {
    @JsFunction
    interface FullFilledCallback {
        void execute(byte[] o);
    }

    @JsFunction
    interface RejectedCallback<T> {
        void execute(byte[] o);
    }

    void then(FullFilledCallback onFulfilled, RejectedCallback onRejected);
}
interface FileReader {
  Thenable<byte[]> readRange(int offset, int length);
}
class FileTest {
  public void doSomething(FileReader reader) {
    reader.readRange(0, 10).then(bytes -> 
       //do something with the bytes
    );
  }
}

In Javascript:

class FileReader {
   readRange(offset, length) {
      return new Promise((resolve, reject) => {
         resolve(new Uint8Array([1, 2]));
      }); 
  }
 let fileTest = new FileTest();
 fileTest.doSomething(new FileReader()) // throws something similar to Error: Class$obf_1003: Class$obf_1001 cannot be cast to [LClass$obf_1002]...
}

Bazel version 5.1.0

gkdn commented 2 years ago

This is because byte[] is not a Uint8Array but it is a Array<number> with extra metadata. We are considering mapping primitive arrays to TypedArray but that's not going to be soon.

If you really would like to use byte[] in JS, one option you have is to create a static function that returns a byte[]. Either the function can take byte parameters and return constructed array: static byte[] createByteArray(byte... bytes){ return bytes;} or you can manipulate returned empty array to add items.

If you care about using Uint8Array from Java side, then you can use Elemental2 or JsArrayLike from the jsinterop.base library.

rbsdc commented 2 years ago

Thank you for the clarification. I already thought that Uint8Array might not be the correct byte[] equivalent, but wondered anyhow why it did work when using a plain byte[] parameter (as described above and in the other issue). Anyway, by using your suggested method static byte[] createByteArray(byte... bytes){ return bytes;} and manipulating the returned array I made it work. Thank you again!