Skip to content

About

Support projects to be GraalVM Native Image compatible

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

36 Commits

Folders and files

Repository files navigation

Class Implementation Index Maven Plugin

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

Features

  • ⚡ 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.

Requirements

  • Java 21
  • Maven 3.9.11

Quickstart

<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

Configuration properties (prefix: codegenConcreteClass.*)

Use dot-notation for class names in the configuration.

codegenConcreteClass.baseClasses (String) — required

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

codegenConcreteClass.usePrecompiledLists (boolean)

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

codegenConcreteClass.verbose (boolean)

Enable extra logging.

  • Default: false

codegenConcreteClass.generateReachabilityMetadata (boolean)

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

codegenConcreteClass.generateReflectConfig (boolean)

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

codegenConcreteClass.reflectedClasses (String)

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

How it works

  1. Parses baseClasses and converts to JVM internal format.
  2. Scans your module’s class files and builds a header map.
  3. For each dependency JAR:
    • If usePrecompiledLists=true and a properties file exists at META-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.
  4. For each base type, the plugin unions precomputed + discovered implementations and writes the final properties file atomically.

Troubleshooting

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

  • baseClasses Has 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

Contract

  • 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.json and legacy reflect-config.json generation are enabled by default.
  • can use it solely for generating Native Image metadata without using the other feature by setting reflectedClasses and not configuring baseClasses.
  • both features can be used independently, and they also work together without conflict

About

Support projects to be GraalVM Native Image compatible

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages