Skip to content

Commit 97c27f6

Browse files
committed
Add README
1 parent a53b4a4 commit 97c27f6

1 file changed

Lines changed: 67 additions & 43 deletions

File tree

  • native-image/web-image/export-java-function
Lines changed: 67 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
# Web Image: Run Java in a Browser
1+
# Web Image: Export Java Method Example
22

3-
This demo illustrates how to take a Java application, compile it ahead-of-time (AOT) using [GraalVM Native Image](https://www.graalvm.org/latest/reference-manual/native-image/), and produce a WebAssembly (WASM) module that can run in browsers or Node.js.
3+
This demo illustrates the use of **Web Image** - an experimental backend for [GraalVM Native Image](https://www.graalvm.org/latest/reference-manual/native-image/) that compiles a Java application ahead-of-time and produces a WebAssembly (WASM) module with a JavaScript wrapper.
4+
Then it can be run in browsers or with Node.js.
45

5-
This demo exposes a simple Java `add(int a, int b)` function to the global JavaScript scope using the `@JS` annotation.
6-
The key idea is that you can **call Java functions directly from JavaScript** without relying on the `main()` method.
6+
The key idea is to show how you can currently **call Java methods directly from JavaScript** without relying on the `main()` method.
7+
This demo exposes a simple Java `add(int a, int b)` method to the global JavaScript scope using the `@JS` annotation from the [Annotation Interface](https://www.graalvm.org/sdk/javadoc/org/graalvm/webimage/api/JS.html).
78

89
> Note: Web Image is an experimental technology and under active development. APIs, tooling, and capabilities may change.
910
@@ -24,65 +25,88 @@ The key idea is that you can **call Java functions directly from JavaScript** wi
2425
```bash
2526
javac Adder.java
2627
```
27-
2. Compile the Java file to WASM using the following command:
28+
2. Compile the application to WASM by passing the `--tool:svm-wasm` option (it should be the first argument):
2829
```bash
29-
native-image --tool:svm-wasm -H:-AutoRunVM HelloWasm
30+
native-image --tool:svm-wasm -H:-AutoRunVM Adder
3031
```
31-
The build produces the following artifacts in the working directory:
32-
- _Adder.java_ – Java source code.
33-
- _index.html_ – HTML file to test the WebAssembly module in the browser.
34-
- _adder.js_ - JavaScript launcher and a runtime wrapper.
35-
- _adder.js.wasm_- Compiled WebAssembly module containing Java code and runtime support (object layout, parts of [Substrate VM](https://github.com/oracle/graal/tree/master/substratevm) adapted for Wasm).
32+
The build produces the following artifacts in the working directory:
33+
- _adder.js_ - a JavaScript runtime wrapper;
34+
- _adder.js.wasm_- the compiled WebAssembly module containing Java code and runtime elements (object layout, parts of [Substrate VM](https://github.com/oracle/graal/tree/master/substratevm) adapted for Wasm);
35+
- _adder.js.wat_ - debug artifacts to understand how Java code and runtime components are lowered to WebAssembly.
3636

37-
3. Run the application in a browser using a simple HTTP server.
37+
3. Run the application in a browser using a simple HTTP server (with Python or Java):
3838
```bash
3939
python3 -m http.server 8000
4040
```
4141
```bash
4242
jwebserver -p 8000
4343
```
44-
Instead of just loading the script, you can attach some logic after the runtime is ready.
44+
Instead of just loading the script, you attach some logic after the runtime is ready.
4545

46-
4. Open the application in the browser: [http://localhost:8000](http://localhost:8000)
46+
4. Navigate to [http://localhost:8000](http://localhost:8000) in the browser. Enter some numbers, click **Add** and see the result displayed.
4747

48-
The generated module depends on JavaScript-provided imports and runtime.
48+
## Review the Sample Application
4949

50-
What actually happens:
51-
1. The `@JS` annotation
52-
- `@JS` is part of GraalVM Web Image API. It allows you to bridge Java and JavaScript.
53-
- `args = {"adder"}`
54-
- This declares that the JavaScript snippet in value will have access to a variable named adder.
55-
- In other words, it tells GraalVM that the BiFunction you pass in Java will be available as a JS variable adder.
56-
- `value = "globalThis.adder = adder;"` - This is raw JavaScript code executed when the export happens.
57-
- `globalThis` is a JavaScript object that is globally accessible in browsers and Node.js (like window in browsers).
58-
- `globalThis.adder = adder;` sets a global JS variable called adder to point to the Java function you passed.
50+
What actually happens? This is the Java source code:
51+
```java
52+
import java.util.function.BiFunction;
53+
import org.graalvm.webimage.api.JS;
54+
import org.graalvm.webimage.api.JSNumber;
5955
60-
So essentially, you are taking a Java method and exposing it as a callable function in JavaScript.
56+
public class Adder {
57+
public static int add(int a, int b) {
58+
return a + b;
59+
}
6160
62-
2. The `export` method
61+
@JS(args = {"adder"}, value = "globalThis.adder = adder;")
62+
private static native void export(BiFunction<JSNumber, JSNumber, JSNumber> adder);
6363
64-
`export((a, b) -> JSNumber.of(add(a.asInt(), b.asInt())));`
65-
- You are passing a Java lambda (BiFunction<JSNumber, JSNumber, JSNumber>) to the export method.
66-
This lambda converts JS numbers (JSNumber) to Java integers, calls your add method, and converts the result back to JSNumber.
67-
When `export` is called, GraalVM runs the `@JS` snippet:
68-
This makes the lambda directly callable from JS as `globalThis.adder(...)`.
64+
public static void main(String[] args) {
65+
export((a, b) -> {
66+
return JSNumber.of(add(a.asInt(), b.asInt()));
67+
});
68+
}
69+
}
70+
```
6971

70-
3. Calling from JavaScript in HTML
71-
```html
72-
GraalVM.run([], {}).then(() => {
73-
document.getElementById("output").innerText += globalThis.adder(1, 99999);
72+
- `@JS` annotation is part of [GraalVM Web Image API](https://www.graalvm.org/sdk/javadoc/org/graalvm/webimage/api/JS.html). It allows you to bridge Java and JavaScript.
73+
- `args = {"adder"}` tells GraalVM that the BiFunction you pass in Java will be available as a JavaScript variable `adder`.
74+
- `value = "globalThis.adder = adder;"` is a raw JavaScript code executed when the export happens; it sets a variable called `adder` to be globally accessible in browsers.
75+
76+
Further down you see the `export` method:
77+
```java
78+
export((a, b) -> {
79+
return JSNumber.of(add(a.asInt(), b.asInt()));
7480
});
7581
```
7682

77-
`GraalVM.run([], {})` initializes the WASM module and the Java runtime inside the browser.
78-
`globalThis.adder(a, b)` calls the Java lambda that you exported.
83+
- A lambda passed in the `export` method converts JS numbers (`JSNumber`) to Java integers, calls the `add` method, and converts the result back to `JSNumber`.
84+
When `export` is called, GraalVM runs the `@JS` snippet.
85+
This makes the lambda directly callable from JS as `globalThis.adder(...)`.
86+
87+
The next part is calling from JavaScript in HTML, which happens in this part of _index.html_:
88+
```js
89+
<script>
90+
GraalVM.run([], {}).then(() => {
91+
...
92+
addButton.addEventListener("click", () => {
93+
const a = parseInt(document.getElementById("num1").value);
94+
const b = parseInt(document.getElementById("num2").value);
95+
96+
// Call the Java add function via WebAssembly
97+
const result = globalThis.adder(a, b);
7998
80-
Step by step:
99+
output.innerText = `Result: ${result}`;
100+
});
101+
...
102+
});
103+
</script>
104+
```
81105
82-
- Reads values from inputs and passed them as `JSNumber` objects to the lambda.
83-
- Calls your Java `add` function via `globalThis.adder(...)`.
84-
- Converts the `result` back to `JSNumber`.
106+
- `GraalVM.run([], {})` initializes the WASM module and the Java runtime inside the browser.
107+
- `globalThis.adder(a, b)` calls the `add` function you exported via WebAssembly.
85108
86-
The application works entirely in the browser with your GraalVM WebAssembly build.
109+
### Conclusion
87110
88-
The focus is on demonstrating direct interaction between Java and JavaScript in the browser via WebAssembly.
111+
The focus of this demo is to demonstrate direct interaction between Java and JavaScript in the browser via WebAssembly.
112+
Note that the [GraalVM Web Image API](https://www.graalvm.org/sdk/javadoc/org/graalvm/webimage/api/JS.html) is still under active development.

0 commit comments

Comments
 (0)