graal icon indicating copy to clipboard operation
graal copied to clipboard

[GR-62854] [Native Image, WASM] The class annotated with @JS.Export isn’t available from JavaScript.

Open treblereel opened this issue 8 months ago • 2 comments

Describe the Issue

The class annotated with @JS.Export isn’t available from JavaScript.

As I understand it, according to the documentation in JSObject and @JS.Export, in order for a Java class to be accessible from JavaScript you simply need to annotate the class with @JS.Export and have it extend JSObject:

package org.treblereel.graalvm.wasm;

import org.graalvm.webimage.api.JS;
import org.graalvm.webimage.api.JSObject;

import java.util.Random;

@JS.Export
public class Randomizer extends JSObject {
  private Random rng = new Random(719513L);

  public byte[] randomBytes(int length) {
    byte[] bytes = new byte[length];
    rng.nextBytes(bytes);
    return bytes;
  }
}

However, when I load it in JavaScript:

GraalVM.run([]).then(vm => {
  console.log("? " + JSON.stringify(vm.exports));
  const Randomizer = vm.exports.org.treblereel.graalvm.wasm.Randomizer;
  const r = new Randomizer();
  const bytes = r.randomBytes(1024);

  console.log("Random bytes: ", bytes);
});

I get:

TypeError: Cannot read properties of undefined (reading 'treblereel')

and it looks like vm.exports doesn’t contain any exports.

One more question: the docs say:

Exported classes should be used with care. Since these classes and all their methods are unconditionally included in the image, this annotation should only be used in cases in which the class is supposed to instantiated from JavaScript. If the JSObject subclass is only instantiated in Java and passed to JavaScript, then there is no need to use the @JS.Export annotation. Furthermore, the authors of exported classes should reduce the amount of code that is reachable from the methods of an exported class.

Let’s imagine this use case: you have a fairly large Java application with lots of dependencies and business logic, so you need to be careful about what you export. Ideally, in my case I’d like to export only a single method that takes a String (JSON/YAML/etc.) and returns a Promise<String>. How can I achieve that?

it would probably be ideal if the svm-wasm-api were published on Maven. Thank you very much!

Using the latest version of GraalVM can resolve many issues.

GraalVM Version

java version "25" 2025-09-16 LTS Java(TM) SE Runtime Environment Oracle GraalVM 25-dev+20.1 (build 25+20-LTS-jvmci-b01) Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 25-dev+20.1 (build 25+20-LTS-jvmci-b01, mixed mode, sharing)

Operating System and Version

macOs 15.3.1 (24D70)

Troubleshooting Confirmation

Run Command

mvn clean package -Pwasm

Expected Behavior

export works

Actual Behavior

there is an exception in the console

Steps to Reproduce

  1. build the repro
  2. run http-server in /web
  3. open browser and check the console

export_wasm.zip

Additional Context

No response

Run-Time Log Output and Error Messages

No response

treblereel avatar May 02 '25 19:05 treblereel

@fniephaus done, thank you

treblereel avatar May 02 '25 19:05 treblereel

Anything related to subclassing JSObject, including @JS.Export doesn't work at all, because we haven't implented that part yet.

I'll let you know once I make progress on this

patrick96 avatar May 03 '25 07:05 patrick96

@patrick96 Hello, may I ask you if you have any progress ? thanks

treblereel avatar Sep 02 '25 03:09 treblereel