Skip to content

Commit 2bfaf55

Browse files
Bernard Horanolyagpl
authored andcommitted
Replace XML parser with Scanner
1 parent 6af2a5f commit 2bfaf55

File tree

1 file changed

+47
-87
lines changed

1 file changed

+47
-87
lines changed

docs/reference-manual/native-image/guides/specify-class-initialization.md

Lines changed: 47 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
---
22
layout: ni-docs
33
toc_group: how-to-guides
4-
link_title: Specify Class Initialization
4+
link_title: Specify Class Initialization Explicitly
55
permalink: /reference-manual/native-image/guides/specify-class-initialization/
66
---
77

88
# Specify Class Initialization Explicitly
99

1010
By default, Native Image initializes application classes at runtime, except for the classes that Native Image proves "safe" for initialization at build time.
11-
However, you can influence the default behavior by specifying the classes to be build-time or run-time initialized explicitly.
11+
However, you can influence the default behavior by explicitly specifying the classes to be initialized at build-time or runtime.
1212
For that, there are two command-line options: `--initialize-at-build-time` and `--initialize-at-run-time`.
1313
You can use these options to specify whole packages or individual classes.
1414
For example, if you have the classes `p.C1`, `p.C2`, … ,`p.Cn`, you can specify that all the classes in the package `p` are to be initialized at build time by passing the following option to `native-image`:
@@ -20,100 +20,62 @@ If you want only class `C1` in package `p` to be initialized at runtime, use:
2020
--initialize-at-run-time=p.C1
2121
```
2222

23-
You can also programmatically specify Class initialization using the [`RuntimeClassInitialization` class](https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java) from the [Native Image Feature interface](https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/Feature.java).
23+
You can also programmatically specify class initialization using the [`RuntimeClassInitialization`] class (https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeClassInitialization.java) from the [Native Image Feature interface](https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/Feature.java).
2424

2525
This guide demonstrates how to build a native executable by running the class initializer at runtime (default behavior), and then at build time, and compares the two approaches.
2626

2727
### Prerequisite
2828
Make sure you have installed a GraalVM JDK.
2929
The easiest way to get started is with [SDKMAN!](https://sdkman.io/jdks#graal).
30-
For other installation options, visit the [Downloads section](https://www.graalvm.org/downloads/).
30+
For other installation options, visit the [Downloads](https://www.graalvm.org/downloads/) section.
3131

3232
## Run a Demo
3333

34-
For the demo part, you will run a simple Java application that uses an XML parser to list some Java talks from 2023.
35-
The parser create records from the XML data and store them in a `List<Talk>` collection.
36-
This approach removes the dependency on the DOM API for storing and manipulating the parsed data.
34+
For the demo, run a simple Java application that parses some Java talks from 2023.
35+
The parser creates records and adds them to a `List<Talk>` collection.
3736

38-
1. Save the following Java source code in a file named _XMLParser.java_:
37+
1. Save the following Java source code in a file named _TalkParser.java_:
3938
```java
40-
import java.io.IOException;
41-
import java.io.StringReader;
4239
import java.util.ArrayList;
4340
import java.util.List;
44-
45-
import javax.xml.parsers.DocumentBuilder;
46-
import javax.xml.parsers.DocumentBuilderFactory;
47-
import javax.xml.parsers.ParserConfigurationException;
48-
49-
import org.w3c.dom.Document;
50-
import org.w3c.dom.NamedNodeMap;
51-
import org.w3c.dom.NodeList;
52-
import org.xml.sax.InputSource;
53-
import org.xml.sax.SAXException;
54-
55-
public class XMLParser {
56-
57-
private static final List<Talk> talks = parseXML("""
58-
<?xml version="1.0" encoding="UTF-8"?>
59-
<talks>
60-
<talk name="Asynchronous Programming in Java: Options to Choose from by Venkat Subramaniam"></talk>
61-
<talk name="Anatomy of a Spring Boot App with Clean Architecture by Steve Pember"></talk>
62-
<talk name="Java in the Cloud with GraalVM by Alina Yurenko"></talk>
63-
<talk name="Bootiful Spring Boot 3 by Josh Long"></talk>
64-
</talks>
65-
""");
66-
67-
private static List<Talk> parseXML(String xmlContents) {
68-
List<Talk> talkList = new ArrayList<>();
69-
try {
70-
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
71-
DocumentBuilder builder = factory.newDocumentBuilder();
72-
Document document = builder.parse(new InputSource(new StringReader(xmlContents)));
73-
74-
NodeList nodeList = document.getElementsByTagName("talk");
75-
for (int i = 0; i < nodeList.getLength(); i++) {
76-
NamedNodeMap attributes = nodeList.item(i).getAttributes();
77-
String name = attributes.getNamedItem("name").getTextContent();
78-
talkList.add(new Talk(name));
79-
}
80-
} catch (ParserConfigurationException | IOException | SAXException e) {
81-
throw new RuntimeException(e);
82-
}
83-
return talkList;
41+
import java.util.Scanner;
42+
43+
public class TalkParser {
44+
private static final List<Talk> TALKS = new ArrayList<>();
45+
static {
46+
Scanner s = new Scanner("""
47+
Asynchronous Programming in Java: Options to Choose from by Venkat Subramaniam
48+
Anatomy of a Spring Boot App with Clean Architecture by Steve Pember
49+
Java in the Cloud with GraalVM by Alina Yurenko
50+
Bootiful Spring Boot 3 by Josh Long
51+
""");
52+
while (s.hasNextLine()) {
53+
TALKS.add(new Talk(s.nextLine()));
8454
}
55+
s.close();
56+
}
8557

86-
public static void main(String[] args) {
87-
System.out.println("Talks loaded via XML:");
88-
for (Talk talk : talks) {
89-
System.out.println("- " + talk.getName());
90-
}
58+
public static void main(String[] args) {
59+
System.out.println("Talks loaded using scanner:");
60+
for (Talk talk : TALKS) {
61+
System.out.println("- " + talk.name());
9162
}
63+
}
9264
}
9365

94-
class Talk {
95-
private final String name;
96-
97-
public Talk(String name) {
98-
this.name = name;
99-
}
100-
101-
public String getName() {
102-
return name;
103-
}
104-
}
66+
record Talk (String name) {}
10567
```
10668

10769
2. Compile the application:
10870
```bash
109-
javac XMLParser.java
71+
javac TalkParser.java
11072
```
11173

11274
3. Build a native executable, explicitly running the class initializer at runtime:
11375
```bash
114-
native-image --initialize-at-run-time=XMLParser,Talk -o runtime-parser XMLParser
76+
native-image --initialize-at-run-time=TalkParser,Talk -o runtime-parser TalkParser
11577
```
116-
You can leave out the `--initialize-at-run-time=XMLParser,Talk` option in this example because these classes are marked for initialization at run time by default.
78+
You can omit the `--initialize-at-run-time=TalkParser,Talk` option in this example because these classes are marked for initialization at run time by default.
11779
The `-o` option specifies the name of the output file.
11880

11981
4. Run and `time` the native application:
@@ -122,56 +84,54 @@ This approach removes the dependency on the DOM API for storing and manipulating
12284
```
12385
On a machine with 16 GB of memory and 8 cores, you should see a result similar to:
12486
```
125-
Talks loaded via XML:
87+
Talks loaded using scanner:
12688
- Asynchronous Programming in Java: Options to Choose from by Venkat Subramaniam
12789
- Anatomy of a Spring Boot App with Clean Architecture by Steve Pember
12890
- Java in the Cloud with GraalVM by Alina Yurenko
12991
- Bootiful Spring Boot 3 by Josh Long
13092
./runtime-parser 0.00s user 0.00s system 52% cpu 0.010 total
13193
```
132-
The application parses the XML data at runtime.
94+
The application parses the text block at runtime.
13395

134-
Check the file size which should be around 19M:
96+
Check the file size which should be around 13M:
13597
```
13698
du -sh runtime-parser
13799
```
138100

139-
5. Next, build a native executable initializing `XMLParser` at build time, and providing a different name for the output file to differentiate it from the previous build. The `Talk` class has to be initialized explicitly too, so the objects of this type will be persisted in the image heap.
101+
5. Next, build a native executable initializing `TalkParser` at build time, and providing a different name for the output file to differentiate it from the previous build. The `Talk` record has to be initialized explicitly too, so the objects of this type will be persisted in the executable heap.
140102
```bash
141-
native-image --initialize-at-build-time=XMLParser,Talk -o buildtime-parser XMLParser
103+
native-image --initialize-at-build-time=TalkParser,Talk -o buildtime-parser TalkParser
142104
```
143105

144-
If your application adds additional types to the image heap, each type (or the corresponding package) needs to be marked for build-time initialization explicitly to fullfil the requirements of `--strict-image-heap`.
106+
If your application adds additional types to the executable heap, each type (or the corresponding package) needs to be marked for build-time initialization explicitly to fulfill the requirements of `--strict-image-heap`.
145107
An appropriate actionable error message will guide you through the process.
146108

147-
Note that in this example, the static analysis optimizes `org.w3c.dom.Document` away.
148-
149109
6. Run and `time` the second executable for comparison:
150110
```bash
151111
time ./buildtime-parser
152112
```
153113
This time you should see something similar to this:
154114
```
155-
Talks loaded via XML:
115+
Talks loaded using scanner:
156116
- Asynchronous Programming in Java: Options to Choose from by Venkat Subramaniam
157117
- Anatomy of a Spring Boot App with Clean Architecture by Steve Pember
158118
- Java in the Cloud with GraalVM by Alina Yurenko
159119
- Bootiful Spring Boot 3 by Josh Long
160120
./buildtime-parser 0.00s user 0.00s system 53% cpu 0.016 total
161121
```
162-
Check the file size which should decrease to around 5.9M!
122+
Check the file size which should decrease to around 6.4M!
163123
```
164124
du -sh buildtime-parser
165125
```
166-
The file size change is because Native Image runs the static initializer at build time, parsing the XML data, and persisting only the `Talks` objects in the executable.
167-
As a result, the majority of the XML parsing infrastructure does not become reachable when Native Image statically analyzes the application and is, therefore, not included in the executable.
126+
The file size change is because Native Image runs the static initializer at build time, parsing the text block, and persisting only the `Talk` records in the executable.
127+
As a result, the majority of the scanning infrastructure does not become reachable when Native Image statically analyzes the application and is, therefore, not included in the executable.
168128

169129
Another valuable criterion for profiling applications more accurately is the number of instructions, which can be obtained using the [Linux `perf` profiler](../PerfProfiling.md).
170130

171131
For example, for this demo application, the number of instructions decreased by almost 30% (from 11.8M to 8.6M) in the case of build-time class initialization:
172132
```bash
173133
perf stat ./runtime-parser
174-
Talks loaded via XML:
134+
Talks loaded using scanner:
175135
- Asynchronous Programming in Java: Options to Choose from by Venkat Subramaniam
176136
(...)
177137
Performance counter stats for './runtime-parser':
@@ -187,7 +147,7 @@ Talks loaded via XML:
187147
```
188148
```bash
189149
perf stat ./buildtime-parser
190-
Talks loaded via XML:
150+
Talks loaded using scanner:
191151
- Asynchronous Programming in Java: Options to Choose from by Venkat Subramaniam
192152
(...)
193153
Performance counter stats for './buildtime-parser':
@@ -202,15 +162,15 @@ Talks loaded via XML:
202162
0.002226000 seconds sys
203163
```
204164

205-
This demonstrates how Native Image can shift work from runtime to build time: when the class is initialized at build time, the XML data is parsed when the executable is being built and only the parsed objects are included.
206-
This not only makes the executable smaller in file size, but also faster to run: when the executable runs, the `Talk` objects already exists and only need to be printed.
165+
This demonstrates how Native Image can shift work from runtime to build time: when the class is initialized at build time, the text block is parsed when the executable is being built and only the parsed objects are included.
166+
This not only makes the executable smaller in file size, but also faster to run: when the executable runs, the `Talk` records already exist and only need to be printed.
207167

208168
To ensure native executables built with Native Image are as compatible as possible with the HotSpot behavior, application classes that cannot be safely initialized at build time, are initialized at runtime.
209169
You as a user, or a framework that you use, must explicitly request build-time initialization for certain classes to benefit from smaller file sizes and faster times to run.
210170
Include the right data structures to avoid the image size blowing up instead.
211-
We also recommend to use `--initialize-at-build-time` with single classes only.
171+
We also recommend using `--initialize-at-build-time` with single classes only.
212172
It may be that you need to add a lot of `--initialize-at-build-time` entries.
213-
Note that incorrect build-time initialization can lead from dysfunctional behavior to including sensitive data such as passwords or encryption keys, problems that are to be avoided in production settings.
173+
Note that incorrect build-time initialization can lead to problems that are to be avoided in production settings such as dysfunctional behavior or including sensitive data such as passwords or encryption keys.
214174

215175
### Conclusion
216176

0 commit comments

Comments
 (0)