Skip to content

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

Open
@treblereel

Description

@treblereel

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. 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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions