You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
4
5
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).
7
8
8
9
> Note: Web Image is an experimental technology and under active development. APIs, tooling, and capabilities may change.
9
10
@@ -24,65 +25,88 @@ The key idea is that you can **call Java functions directly from JavaScript** wi
24
25
```bash
25
26
javac Adder.java
26
27
```
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):
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.
36
36
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):
38
38
```bash
39
39
python3 -m http.server 8000
40
40
```
41
41
```bash
42
42
jwebserver -p 8000
43
43
```
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.
45
45
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.
47
47
48
-
The generated module depends on JavaScript-provided imports and runtime.
48
+
## Review the Sample Application
49
49
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 functionyou 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;
59
55
60
-
So essentially, you are taking a Java method and exposing it as a callable functionin JavaScript.
56
+
public class Adder {
57
+
public static int add(int a, int b) {
58
+
return a + b;
59
+
}
61
60
62
-
2. The `export` method
61
+
@JS(args = {"adder"}, value = "globalThis.adder = adder;")
- `@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()));
74
80
});
75
81
```
76
82
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 functionvia WebAssembly
97
+
const result = globalThis.adder(a, b);
79
98
80
-
Step by step:
99
+
output.innerText = `Result: ${result}`;
100
+
});
101
+
...
102
+
});
103
+
</script>
104
+
```
81
105
82
-
- Reads values from inputs and passed them as `JSNumber` objects to the lambda.
83
-
- Calls your Java `add`functionvia`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`functionyou exported via WebAssembly.
85
108
86
-
The application works entirely in the browser with your GraalVM WebAssembly build.
109
+
### Conclusion
87
110
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