How to Build a Minimal GraalVM Native Image for a Solon Java App

This guide walks through setting up GraalVM on Ubuntu, configuring environment variables, handling native-image agent pitfalls, fixing H2 database class‑loading issues, and finally producing a compact native executable for a Solon‑based Java service with memory‑optimisation tips.

Programmer DD
Programmer DD
Programmer DD
How to Build a Minimal GraalVM Native Image for a Solon Java App

Environment

System: Ubuntu 16.04

GraalVM: GraalVM Community 21.3.0 (based on OpenJDK 11.0.13)

Preparation

Set JAVA_HOME to the GraalVM directory

Add $JAVA_HOME/bin to

PATH
export JAVA_HOME=/path/to/graalvm
export PATH=$JAVA_HOME/bin:$PATH

Install the native‑image tool: gu install native-image Install required build packages:

apt-get install build-essential libz-dev zlib1g-dev

Note: The linker ld must be version 2.26+; otherwise the build will fail.

Packaging

First build the project JAR with Maven (e.g., solondemo.jar) and verify it runs: java -jar solondemo.jar Collect configuration data with the native‑image agent (skip if the project does not use reflection or proxies):

java -agentlib:native-image-agent=config-output-dir=./config/ -jar solondemo.jar

Run tests to achieve near‑100% coverage, then merge the generated config files if needed:

java -agentlib:native-image-agent=config-merge-dir=./config/ -jar solondemo.jar

The agent produces five JSON files ( jni-config.json, predefined-classes-config.json, proxy-config.json, reflect-config.json, resource-config.json, serialization-config.json) that must be packaged into META-INF/native-image or supplied via -H:ConfigurationFileDirectories=./config. On Ubuntu the latter works; on CentOS it may be mis‑interpreted.

Because GraalVM treats resources differently, scanning directories like META-INF/solon fails. The workaround is to pre‑list required files and make the resource scanner treat them as regular files.

Fixing H2 Database Issues

The native image initially fails with ClassNotFoundException for H2 file‑system classes. Adding the missing classes to reflect-config.json resolves the problem. Example entry:

{"name":"org.h2.store.fs.FilePathDisk","methods":[{"name":"<init>","parameterTypes":[]} ]}

Repeat until all required classes are covered.

Final Native‑Image Command

native-image -jar solondemo.jar \
  --allow-incomplete-classpath \
  -H:+ReportExceptionStackTraces \
  --enable-http

Use --enable-https if HTTPS is required. The resulting binary runs correctly, serving HTTP endpoints, static pages, and logging.

Additional Tips

The native‑image agent may miss some reflective calls; manually add them to reflect-config.json.

GraalVM’s custom file system cannot traverse directories; pre‑configure file lists.

Third‑party libraries often fail due to missing reflection metadata.

Native‑image builds need >5 GB RAM; set memory limits with -Xmx and -XX:MaxDirectMemorySize when running the binary.

References

GraalVM download: https://www.graalvm.org/downloads/

Native‑image quick reference PDF (linked in the original article).

Solon framework source: https://gitee.com/noear/solon

Demo project: https://gitee.com/mantouchong/solondemo

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javagraalvmnative-imageh2Solon
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.