Skip to content

Commit 872ef4d

Browse files
committed
TW runthrough
1 parent 9123e28 commit 872ef4d

File tree

2 files changed

+59
-48
lines changed

2 files changed

+59
-48
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Demos for building native images, including configurations and setup steps for v
2828
* [list-files](native-image/list-files/) - Shows how to create a native executable from the command line, and then apply Profile-Guided Optimization (PGO)
2929
* [native-build-tools](native-image/native-build-tools/) - Contains two Java projects, and shows how to create native executables from those applications using [Maven](https://graalvm.github.io/native-build-tools/latest/maven-plugin.html) and [Gradle](https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html) plugins for GraalVM Native Image
3030
* [wasm-javac](native-image/wasm-javac/) - Illustrates how to use the new experimental WebAssembly backend in GraalVM to compile `javac` into a Wasm module, which can then run either on the command line or in the browser. [Check out the live demo here](https://graalvm.github.io/graalvm-demos/native-image/wasm-javac/).
31-
* [preserve-package](native-image/preserve-package/) - Demonstrates how to use the -H:Preserve option to include all classes in a package in a native image instead of using JSON metadata configuration.
31+
* [preserve-package](native-image/preserve-package/) - Demonstrates how to use the `-H:Preserve` option to include all classes from a package in a native image, eliminating the need for JSON metadata configuration.
3232

3333
### Configure
3434
Demos illustrating how to compile applications with Native Image that use some dynamic Java features including reflection, resource access, and so on.

native-image/preserve-package/README.md

Lines changed: 58 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
# Using Native Image `Preserve` Option
22

3-
[Reflection](https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/reflect/package-summary.html) is a feature of the Java programming language that enables a running Java program to examine and modify attributes of its classes, interfaces, fields, and methods and GraalVM Native Image provides automatic support for some uses. Native Image uses static analysis to identify what classes, methods, and fields are needed by an application but it may not detect some elements of your application that are accessed using the [Java Reflection API](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/package-summary.html). Undetected Reflection usage must be declared to the `native-image` tool either in the form of metadata (precomputed in code or as JSON configuration files) or using the `-H:Preserve` option (experimental in GraalVM for JDK 25).
3+
[Reflection](https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/lang/reflect/package-summary.html) is a feature of the Java programming language that enables a running Java program to examine and modify attributes of its classes, interfaces, fields, and methods. GraalVM Native Image automatically supports some uses of reflection. Native Image uses static analysis to identify what classes, methods, and fields are needed by an application, but it may not detect some elements of your application that are accessed using the [Java Reflection API](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/reflect/package-summary.html). You must declare any undetected reflection usage to the `native-image` tool, either as metadata (precomputed in code or as JSON configuration files) or using the `-H:Preserve` option (experimental in GraalVM for JDK 25).
44

5-
The following demonstrates how to declare Reflection configuration using the `-H:Preserve` option.
5+
This guide demonstrates how to declare reflection configuration using the `-H:Preserve` option.
66

77
## Preparation
88

9-
1. Download and install the latest GraalVM for JDK 25 (or early access build before 2025-09-16) using [SDKMAN!](https://sdkman.io/).
9+
1. Download and install the latest GraalVM for JDK 25 (or the early access build before 2025-09-16) using [SDKMAN!](https://sdkman.io/).
1010

1111
```shell
1212
sdk install java 25.ea.29-graal
@@ -16,15 +16,12 @@ The following demonstrates how to declare Reflection configuration using the `-H
1616

1717
```shell
1818
git clone https://github.com/graalvm/graalvm-demos
19-
```
20-
21-
```shell
2219
cd graalvm-demos/native-image/preserve-package
2320
```
2421

2522
## Example using Reflection on the JVM
2623

27-
The `ReflectionExample` class will use command line argument values to
24+
The `ReflectionExample` class uses command line argument values to
2825
reflectively create an instance of a class and invoke a method with a
2926
provided argument. The core code is:
3027

@@ -34,14 +31,15 @@ provided argument. The core code is:
3431
Object result = method.invoke(null, input);
3532
```
3633

37-
This works fine when running the JVM and the named classes and methods are on
38-
the application classpath.
34+
This approach works on the JVM as long as the required classes and methods are available on the classpath.
35+
36+
1. Compile the application and create a JAR file using Maven:
3937

40-
1. Compile the application and create a jar using Maven:
4138
```shell
4239
./mvnw package
4340
```
44-
2. Run `ReflectionExample` (the jar entry point) and instruct it to invoke the
41+
42+
2. Run `ReflectionExample` (the JAR entry point) to invoke the
4543
`StringReverser` action:
4644

4745
```shell
@@ -50,38 +48,47 @@ the application classpath.
5048
```
5149

5250
Expected output:
51+
5352
```shell
5453
olleh
5554
```
5655

57-
3. Do the same for the `StringCapitalizer` action:
56+
3. Run the same command for the `StringCapitalizer` action:
57+
5858
```shell
5959
$JAVA_HOME/bin/java -jar target/preserve-package-1.0-SNAPSHOT.jar \
6060
org.graalvm.example.action.StringCapitalizer capitalize "hello"
6161
```
62+
6263
Expected output:
64+
6365
```shell
6466
HELLO
6567
```
6668

6769
## GraalVM Native Image
6870

69-
We can compile with Native Image specifying the `ReflectionExample` as the main
70-
entry point. The project [`pom.xml`](pom.xml) uses the [GraalVM Native Build
71-
Tools](https://graalvm.github.io/native-build-tools/latest/index.html) plugin to
72-
compile the project using the `native-image` tool when the `native-default`
73-
profile is specified.
71+
You can compile the project with Native Image, specifying `ReflectionExample` as the main
72+
entry point.
73+
The [_pom.xml_](pom.xml) file uses the [GraalVM Native Build
74+
Tools](https://graalvm.github.io/native-build-tools/latest/index.html) plugin to compile the project with the `native-image` tool when you select the `native-default`
75+
profile.
76+
77+
1. Build a native executable using the `native-default` profile (see the [_pom.xml_](pom.xml) file):
7478

75-
1. Build a native executable using the `native-default` profile (see [`pom.xml`](pom.xml)):
7679
```shell
7780
./mvnw package -Pnative-default
7881
```
79-
4. Run the resulting `example-default` native executable, using the following command:
82+
83+
2. Run the resulting `example-default` native executable:
84+
8085
```bash
8186
./target/example-default \
8287
org.graalvm.example.action.StringReverser reverse "hello"
8388
```
84-
You will see a `ClassNotFoundException` exception, similar to:
89+
90+
You will see a `ClassNotFoundException` similar to:
91+
8592
```shell
8693
Exception in thread "main" java.lang.ClassNotFoundException: org.graalvm.example.action.StringReverser
8794
at org.graalvm.nativeimage.builder/com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:339)
@@ -92,26 +99,21 @@ profile is specified.
9299
at org.graalvm.example.ReflectionExample.main(ReflectionExample.java:56)
93100
at java.base@25/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)
94101
```
95-
What happened!? Based on its static analysis, the `native-image` tool was unable
96-
to determine that class `StringReverser` is used by the application and
97-
therefore did not include it in the native executable.
98102

99-
## Native Image using -H:Preserve
103+
This error occurs because the `native-image` tool's static analysis did not determine that your application uses the `StringReverser` class, and did not include it in the native executable.
104+
105+
## Native Image using `-H:Preserve`
106+
107+
GraalVM for JDK 25 introduces the `-H:Preserve` option.
108+
109+
This option lets you instruct the `native-image` tool to keep entire packages, modules, or all classes on the classpath
100110
101-
New in GraalVM for JDK 25 is the `-H:Preserve` option which makes it easy to instruct the
102-
`native-image` tool to preserve (i.e., keep entirely) packages, modules, and
103-
even all classes on the classpath (which can result in very large applications).
111+
<!-- (which can result in very large applications). -->
104112
105-
Conveniently in this example, both of the classes that are being used via
106-
reflection are in the `org.graalvm.example.action` package. We can use
107-
`-H:Preserve=package` to keep all of the classes in that package in the native
108-
executable, even though their use is not discoverable through static analysis.
113+
In this example, both classes used via reflection are in the `org.graalvm.example.action` package. You can use `-H:Preserve=package` to keep all of the classes in that package in the native executable, even if static analysis cannot discover them.
109114
110115
Native Image command line arguments can be specified as `<buildArgs>` in the
111-
`native-maven-plugin` configuration. Note that since the `-H:Preserve` option
112-
is new and considered experimental in GraalVM for JDK 25, you must also enable
113-
its use with `-H:+UnlockExperimentalVMOptions`. See the [`pom.xml`](pom.xml) for
114-
the complete plugin configuration:
116+
`native-maven-plugin` configuration. As the `-H:Preserve` option is experimental, you must also enable its use with `-H:+UnlockExperimentalVMOptions`. For the complete plugin configuration, see the [_pom.xml_](pom.xml) file:
115117
116118
```xml
117119
<configuration>
@@ -123,33 +125,42 @@ the complete plugin configuration:
123125
</configuration>
124126
```
125127
126-
1. Build a native executable using the `native-preserve` profile which adds
128+
1. Build a native executable using the `native-preserve` profile, which adds
127129
`-H:Preserve=package=org.graalvm.example.action` when running the `native-image`
128-
tool (see [`pom.xml`](pom.xml)):
130+
tool (see the [_pom.xml_](pom.xml) file):
131+
129132
```shell
130133
./mvnw package -Pnative-preserve
131134
```
132135
133136
2. Run the new `example-preserve` executable to confirm the previously missing
134-
`StringReverser` class and all its methods are now included:
137+
`StringReverser` class and its methods are now included:
138+
135139
```shell
136140
./target/example-preserve \
137141
org.graalvm.example.action.StringReverser reverse "hello"
138142
```
139-
The expected "olleh" output should be the result, just like on the JVM.
140143
141-
3. Invoke the `StringCapitalizer` to see if that now works too:
142-
144+
Expected output:
145+
146+
```shell
147+
olleh
148+
```
149+
150+
3. Run the executable to confirm the `StringCapitalizer` class works too:
151+
143152
```shell
144153
./target/example-preserve \
145154
org.graalvm.example.action.StringCapitalizer capitalize "hello"
146155
```
147-
The expected "HELLO" output should be the result.
148-
149-
150-
As demonstrated, `-H:Preserve` provides an easy way to ensure classes not
151-
discovered by GraalVM Native Image's static analysis are included in an
152-
executable.
156+
157+
Expected output:
158+
159+
```shell
160+
HELLO
161+
```
162+
163+
As demonstrated, `-H:Preserve` provides an easy way to ensure that Native Image includes classes not discovered by static analysis.
153164
154165
### Related Documentation
155166

0 commit comments

Comments
 (0)