skip to content

What is the metadataRepository configuration in native-maven-plugin, and how does it relate to the GraalVM Reachability Metadata Repository?

level: seniorimportance: should knowfreq 30%

answer

  1. community repo: group:artifact:version -> native-image metadata
  2. add-reachability-metadata goal puts it on classpath
  3. Spring Boot enables it by default
  4. covers third-party libs; AOT covers your app
  5. pin version / local url / force for reproducibility

basics

~20 s

metadataRepository enables the plugin to pull reachability metadata (reflection, resources, JNI, proxies) for third-party libraries from the GraalVM Reachability Metadata Repository, so libraries that don't ship their own hints still work in a native image. Spring Boot enables it by default.

solid answer

~40 s

The GraalVM **Reachability Metadata Repository** is a community-maintained, versioned collection of native-image metadata (reflect/resource/jni/proxy/serialization config) for popular Java libraries that don't embed their own. The plugin's `<metadataRepository><enabled>true</enabled></metadataRepository>` config makes the `add-reachability-metadata` goal fetch matching metadata by group:artifact:version and place it on the image build classpath. Spring Boot's `native` profile enables it by default, so libraries like drivers, JSON/HTTP clients, and logging frameworks work without you writing manual `RuntimeHints`. You can pin a `<version>`, point at a local `<url>`, or `<force>` a version, and exclude specific artifacts. It complements Spring AOT: AOT covers your app and Spring beans; the metadata repo covers third-party libs. If a library lacks metadata both in its jar and the repo, you still need manual hints or an agent trace.

code

java · 27 lines
java
// pom.xml — enabling and pinning the reachability metadata repository (Java-comment block).
//
// <plugin>
//   <groupId>org.graalvm.buildtools</groupId>
//   <artifactId>native-maven-plugin</artifactId>
//   <configuration>
//     <metadataRepository>
//       <enabled>true</enabled>            <!-- Spring Boot default -->
//       <version>0.3.4</version>           <!-- pin for reproducible builds -->
//       <dependencies>
//         <dependency>
//           <groupId>com.example</groupId>
//           <artifactId>legacy-lib</artifactId>
//           <force>true</force>            <!-- use nearest metadata when no exact match -->
//         </dependency>
//       </dependencies>
//     </metadataRepository>
//   </configuration>
// </plugin>
//
// If a library has NO repo metadata at all, supply hints yourself instead:
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.context.annotation.Configuration;

@Configuration
@RegisterReflectionForBinding(com.example.dto.LegacyPayload.class)
class NativeHintsConfig { }

go deeper

for a junior

Know it supplies native-image metadata for third-party libraries and is on by default in Spring Boot.

for a middle

Explain add-reachability-metadata resolving by coordinates and how it complements Spring AOT.

for a senior

Pin/force versions, use local mirrors for reproducibility, and triage missing-metadata runtime failures.

for a principal

Own a reproducible, mirrored metadata strategy and a policy for contributing/overriding metadata across services.

## The problem it solves GraalVM native-image is closed-world: any reflection, resource load, JNI call, dynamic proxy, or serialization a library performs must be **declared** as metadata, or it breaks at runtime. Well-behaved libraries ship this metadata inside their jar under `META-INF/native-image/...`. Many libraries — especially older or transitive ones — do **not**. That's what the **GraalVM Reachability Metadata Repository** fixes: a central, open-source, community-curated repo mapping `groupId:artifactId:version` → the metadata JSON that makes that library work natively. ## The plugin configuration `native-maven-plugin` integrates with it via: ``` <configuration> <metadataRepository> <enabled>true</enabled> <!-- optional overrides: --> <version>0.3.x</version> <!-- pin the repo release --> <url>file:///path/to/local-repo</url> <!-- use a local/custom repo --> <dependencies> <!-- force/exclude per artifact --> <dependency> <groupId>...</groupId><artifactId>...</artifactId> <force>true</force> </dependency> </dependencies> </metadataRepository> </configuration> ``` When enabled, the **`native:add-reachability-metadata`** goal (bound before the compile goal) resolves your dependency coordinates against the repo and puts any matching metadata onto the classpath the image build sees. By default it matches the exact library versions; `force` lets you use metadata from a different version when an exact match is missing. ## Spring Boot defaults Spring Boot's `native` profile turns `metadataRepository` **on by default**, so most apps get third-party coverage for free. This is why a typical Spring Boot native app with common starters builds and runs without hand-written hints for the framework's own dependencies. ## How it complements Spring AOT Think of two metadata sources: 1. **Spring AOT (`process-aot`)** — covers *your* application code and Spring's bean model, plus any `RuntimeHintsRegistrar` contributed by Spring/starter libraries. 2. **Reachability Metadata Repository** — covers *third-party* libraries' internal reflection/resource needs that Spring can't infer. Both feed the same native-image build; together they cover the bulk of a normal app. ## Edge cases & gotchas - **Version mismatch:** if you use a library version newer than what the repo has, metadata may be missing; pin a repo version, use `force`, or contribute upstream. - **Still not exhaustive:** a niche library with no jar metadata and no repo entry still needs manual `RuntimeHints`/`@RegisterReflectionForBinding` or a **tracing agent** run (`java -agentlib:native-image-agent=...`) to generate config, copied in via `native:metadata-copy`. - **Reproducibility:** for hermetic/offline builds, pin the `<version>` (or host a mirror via `<url>`) so builds don't silently change when the community repo updates. - **Disabling:** setting `<enabled>false</enabled>` (or Spring's property) turns it off — you then own all third-party metadata yourself, which you'd rarely want. ## When to touch it Leave it enabled. Reach for the overrides only when: a dependency's metadata is missing/wrong (force a version), you need offline/reproducible builds (pin/local url), or you must exclude a bad metadata entry. If you hit a runtime reflection error natively, first check whether the offending library has (or lacks) repo metadata before writing manual hints.

  • Your native app throws a reflection error for a third-party class. What's your triage order?
    First check if the library ships its own META-INF/native-image metadata; if not, check whether the reachability metadata repo has an entry for that group:artifact:version (pin/force if a version mismatch). Only if both are absent do you write manual RuntimeHints/@RegisterReflectionForBinding or run the tracing agent to generate config.
  • Why pin the metadataRepository version for CI builds?
    The community repo evolves; an unpinned build can pull different metadata over time, making builds non-reproducible or silently breaking. Pinning a version (or mirroring via a local url) makes native builds hermetic and repeatable.

saying these in an interview costs you the question

  • Thinking the metadata repo replaces Spring AOT (it complements it)
  • Assuming it guarantees every library works with no manual hints
  • Not knowing Spring Boot enables it by default
  • Believing metadata lives in buildArgs rather than JSON config from the repo/AOT

context