This plugin enables developers to make their applications GraalVM Native Image compatible. It automatically
generates GraalVM reachability metadata required by Native Image to manage reflection in a controlled and predictable
way, improving startup performance and reducing binary size. By default, it writes both the current
reachability-metadata.json file and the legacy reflect-config.json file for gradual migration.
By limiting reflection to only the explicitly generated and necessary classes, the plugin ensures optimized runtime
behavior with minimal overhead.
This also generates a .properties index of all concrete implementations of one or more base types (abstract
classes) found in your project and its dependencies which are candidates for reflection.
It writes to:
META-INF/io/github/absketches/plugin/services.properties
META-INF/native-image/<group>/<artifact>/reachability-metadata.json
META-INF/native-image/<group>/<artifact>/reflect-config.json
Each key is a dotted base class; each value is a comma‑separated list of dotted implementation classes.
Example output:
org.nanonative.nano.core.model.Service=org.nanonative.devconsole.service.DevConsoleService,org.nanonative.nano.services.http.HttpServer
org.nanonative.nano.core.NanoServices=org.nanonative.nano.core.Nano- ⚡ Fast: Inspects only .class headers (no ASM, no classloading).
- 📦 Works across dependencies: Operates seamlessly across the current module and all resolved JARs.
- 🧹 Memoized Lookups: Caches discovered superclass chains in memory to eliminate redundant scans.
- 🔒 Zero intrusion: Requires no developer annotations or code changes - ideal for GraalVM native image workflows.
- Java 21
- Maven 3.9.11
<plugin>
<groupId>io.github.absketches</groupId>
<artifactId>codegen-concrete-classes-maven-plugin</artifactId>
<version>${codegen-mvn-plugin.version}</version>
<executions>
<execution>
<id>impl-index</id>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<baseClasses>org.nanonative.nano.core.model.Service,org.nanonative.nano.core.NanoServices</baseClasses>
<outputFile>services.properties</outputFile>
<usePrecompiledLists>true</usePrecompiledLists>
<generateReachabilityMetadata>true</generateReachabilityMetadata>
<generateReflectConfig>false</generateReflectConfig>
<verbose>true</verbose>
</configuration>
</execution>
</executions>
</plugin>Invoke:
mvn codegen-concrete-classes:generate
Use dot-notation for class names in the configuration.
Comma‑separated list of abstract base types (abstract classes) whose concrete implementations you want to index?
- Default: empty (must be provided)
- Example:
io.github.absketches.sentinel.Notification, org.nanonative.nano.core.model.Service
If true, when a dependency JAR already contains a properties file at the same location, i.e. *
*META-INF/io/github/absketches/plugin/**,
those entries are merged in. If a JAR’s precomputed file is missing some configured bases, that JAR is **scanned
** to fill gaps.
- Default:
true
Enable extra logging.
- Default:
false
Merges an existing reachability-metadata.json or creates a new one to enable modern GraalVM Native Image builds.
Generated reflection metadata is written under the top-level reflection section, and existing sections such as
resources are preserved.
- Default:
true
Merges an existing reflect-config.json or creates a new one for older GraalVM Native Image builds and projects that
are still migrating metadata gradually.
- Default:
true
Comma-separated list of concrete classes that should be forced into the generated Native Image metadata. The plugin
will still create or merge metadata when this list is non-empty, even if no implementations were found for the configured
baseClasses.
- Default: empty
- Parses
baseClassesand converts to JVM internal format. - Scans your module’s class files and builds a header map.
- For each dependency JAR:
- If
usePrecompiledLists=trueand a properties file exists atMETA-INF/io/github/absketches/plugin/, it is read and filtered by your configured base types. - If the file is absent or does not include all the base types(incomplete), the JAR is scanned to populate headers.
- If
- For each base type, the plugin unions precomputed + discovered implementations and writes the final properties file atomically.
No services.properties in the JAR
- The plugin isn’t bound to that module?
- The module didn’t produce classes (empty sources or skipped compile)?
Empty services.properties
baseClassesHas baseClasses FQCN changed or does the module have any implementations at all?- Get verbose logging output using -DcodegenConcreteClass.verbose=true
Step-through debug Run this in the IDE of your project which includes this plugin:
mvnDebug process-classes
# Attach the debugger of the plugin project (this) to localhost:8000- must configure at least one base class to generate services metadata.
- Only concrete subclasses of configured super classes are listed.
- Scans compile + runtime classpath.
reachability-metadata.jsonand legacyreflect-config.jsongeneration are enabled by default.- can use it solely for generating Native Image metadata without using the other feature by setting
reflectedClassesand not configuringbaseClasses. - both features can be used independently, and they also work together without conflict