When the Swing program uses exe4j to generate executable files, the startup of large files is slow and cannot meet product-level requirements. The executable file packaged through GraalVM’s native-image tool is about 45M, and the startup time is basically controlled to the millisecond level.
The Swing runtime uses some JNI and reflection classes. The static analyzer cannot predict all reachable codes and requires us to provide some metadata information. Manually editing metadata is troublesome and error-prone. GraalVM provides a native-image-agent tool to collect these class information and save it to reflect-config.json, jni-config.json, resource-config.json, proxy-config.json, serialization-config.json and predefined -classes-config.json These 6 json format configuration files. Of course, if you are familiar with the libraries or classes you need to use, you can also write these files manually.
1. Create Swing project
A Java project was created directly through IDEA. In order to facilitate the creation of executable jar packages, Maven support was added. We create a minimalist GUI program, which generates the following interface after startup:
2. Packaging executable JAR
There are two optional ways, create a Maven project directly through IDEA; or create the project first, right-click on the project and select “Add Framework Support” and select “Maven” to convert the project into a Maven project.
Here we choose maven-shade-plugin and configure the following content in your Maven configuration file:
<?xml version="1.0" encoding="UTF-8"?> <project> <modelVersion>4.0.0</modelVersion> <groupId>com.randy.graalvm</groupId> <artifactId>swing</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.5.1</version> <configuration></configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.company.SwingDemo</mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
After executing mvn package to complete the packaging, the following file will be generated. Double-click to run it to confirm that it has been packaged correctly.
3. Collect metadata
The Swing program uses some code that cannot be identified through static analysis (such as JNI). The java command line parameter-agentlib provided by GraalVM helps us collect metadata.
Here we use swing-1.0.jar to practice the process of collecting metadata.
3.1 Setting environment variables
Make sure the java command uses GraalVM
set GRAALVM_HOME=D:\Programs\GraalVM set PATH=D:\Programs\GraalVM\bin
3.2 Run JAR program
This jar file is an executable jar packaged by Maven. Execute the jar file with the following command, click on each function, and ensure that all required classes are loaded.
java -cp swing-1.0.jar -agentlib:native-image-agent=config-output-dir=d:/tempDir com.company.SwingDemo
As shown in the command line, the collected metadata will be saved under d:/tempDir.
4. Copy metadata to jar
Place the configuration file under META-INF/native-image/${groupId}/${artificatId}, as shown below:
After the copy is completed, use the mvn package command to regenerate the executable jar.
5. Generate executable file
native-image -jar swing-1.0-SNAPSHOT.jar
Commonly used configuration items when building native-image
Configuration items |
describe |
-H: + ReportExceptionStackTraces |
Show exception stack trace during build |
–no-fallback |
Build a native image that does not depend on JVM or show build failure |
–allow-incomplete-classpath |
Allow building with incomplete classpath, this parameter is suitable for libraries that rely on weak references |
-H:ConfigurationFileDirectories=native-image |
Configure the configuration file directory address of the collected meta information |
-H: +AddAllCharsets |
Supports all character sets |
–report-unsupported-elements-at-runtime |
Report unsupported methods and fields only when running the native image instead of reporting errors during the build |
–enable-url-protocols=https,http |
Supported URL protocols. Failure to add this parameter will result in inability to access the web address. |
The execution log is as follows. Through the log, you can see that there are a total of 8 steps in the construction. Even our simplest program takes 2 minutes.
6. Copy fontconfig.bfc
The contents of the directory after the construction is completed are as shown in the figure below. The program can be started through swing-1.0-SNAPSHOT.exe.
Unfortunately, the current swing-1.0-SNAPSHOT.exe cannot run successfully. When running through the cmd command line, I received the following error:
Until I added the following code in the first line of the main method of the program to set the java.home attribute
System.setProperty("java.home", ".");
After recompiling and executing it again, it still failed, but there was an error, the font was wrong.
I copied lib/fontconfig.bfc in the Java installation directory into the compilation result. The final directory looks like this
The final running result is as follows
7. Remove console
At this point, the above executable file can be executed correctly, but there is an additional command line window behind it, through the editon tool
editbin /subsystem:windows swing-1.0-SNAPSHOT.exe
window output
At this point, we have got an exe file that can be executed correctly without any redundant command line windows.