skip to content

@RegisterReflectionForBinding

@RegisterReflectionForBinding declares the DTOs that Jackson or validation will touch reflectively, which is the most common hint an application actually needs. A short annotation that fixes the majority of native serialization failures.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

explore

questions

5

Why do you need @RegisterReflectionForBinding when compiling a Spring app to a GraalVM native image?

level: juniorimportance: should knowfreq 30%

answer

  1. Closed-world analysis drops reflective members
  2. Jackson/validation bind DTOs by reflection
  3. Emits reflect-config.json at AOT time
  4. No-op on the JVM, only matters for native
  5. For types Spring can't auto-detect

basics

~20 s

GraalVM native images strip out code that isn't reachable at build time, and reflection is invisible to that analysis. @RegisterReflectionForBinding tells the build to keep reflection metadata for DTOs so libraries like Jackson can still serialize/deserialize them at runtime.

solid answer

~40 s

A GraalVM native image does closed-world analysis at build time: anything it can't prove is reachable — including types accessed reflectively — is removed, and no reflection metadata is generated for them. Jackson (and Bean Validation) serialize/deserialize DTOs by reflecting over constructors, fields, and accessor methods. If those types have no reflection hints, at runtime you get errors or empty/failed binding. @RegisterReflectionForBinding is a declarative Spring annotation you place on a bean or config class listing the DTO types that are bound (JSON request/response bodies, etc.). During Spring's AOT processing it emits the GraalVM reachability metadata (reflect-config.json under META-INF/native-image) so those types keep their reflective members. On the JVM it's a no-op; it only matters for native.

go deeper

for a junior

Should know native images strip unreachable code, reflection is invisible to that, and this annotation preserves DTOs for Jackson.

for a middle

Should add that hints are emitted at AOT build time as reflect-config.json and are a no-op on the JVM.

for a senior

Should explain closed-world analysis, which binding types Spring auto-detects vs. needs help with, and failure modes at native runtime.

for a principal

Should connect to the broader RuntimeHints model and reachability-metadata generation, and reason about testing strategy for native binaries.

## The core problem A GraalVM *native image* is an ahead-of-time (AOT) compiled binary. Unlike the JVM, which loads classes lazily and can reflect over anything on the classpath, native-image compilation does *closed-world static analysis*: at build time it computes the set of classes, methods, and fields that are provably reachable from the entry point, and everything else is discarded to shrink the binary and enable optimizations. Crucially, **reflection is opaque to this analysis** — a call like `clazz.getDeclaredConstructor().newInstance()` or Jackson walking a type's getters cannot be traced statically, so those members are dropped and *no reflection metadata* is retained for them. ## Where this bites Spring apps Serialization libraries bind data by reflection: - **Jackson** constructs your DTO via its constructor and reads/writes fields or getter/setter methods; - **Bean Validation** reflects over fields/getters to run constraints. If a DTO used as a `@RequestBody`/`@ResponseBody`, or in a `RestClient`/`WebClient` body, has no reflection hints, the native runtime can throw errors or silently produce empty objects. ## What `@RegisterReflectionForBinding` does It is a Spring Framework annotation (since 6.0) that you place on any Spring bean, `@Configuration` class, or even a method (`@Target({TYPE, METHOD})`). You list the DTO types to keep: - `@RegisterReflectionForBinding(MyDto.class)` or - `@RegisterReflectionForBinding(classes = {A.class, B.class})`. During **Spring AOT processing** (which runs at build time, e.g. via the `native` or `nativeCompile`/`processAot` steps), Spring generates GraalVM *reachability metadata* — historically `reflect-config.json` files under `META-INF/native-image/` — so the listed types (and, for binding, the types reachable through their properties) retain the reflective members needed for serialization/deserialization. ## On the JVM it does nothing These hints are only consulted by the native-image builder. Running on the normal JVM, the annotation is inert, so it is safe to leave in place. ## When you actually need it Spring's AOT engine already auto-detects many binding types — for example DTOs directly referenced by `@RequestMapping` controller method signatures. You reach for `@RegisterReflectionForBinding` for types Spring *can't* infer: - bodies passed to `RestClient`/`RestTemplate`/`WebClient` at runtime, - types resolved only through generics or `ParameterizedTypeReference`, - types deserialized manually with an `ObjectMapper`, - or polymorphic subtypes. It saves you from hand-writing `reflect-config.json` or a `RuntimeHintsRegistrar`. ## Key takeaways / gotchas - (1) It's a *build-time* mechanism — you must rebuild the native image for changes to take effect. - (2) It's for *reflection*, not for resources, proxies, or serialization-interface hints (those have their own hint types). - (3) Missing hints often fail loudly at native runtime, not at build time, so integration tests against the native binary matter.

  • Does @RegisterReflectionForBinding change anything when you run on the ordinary JVM?
    No. The reflection hints it produces are only consumed by the GraalVM native-image builder. On the JVM the annotation is effectively a no-op, so it's harmless to keep in the codebase.
  • How does Spring turn the annotation into something GraalVM understands?
    Spring's AOT processing runs at build time and writes GraalVM reachability metadata (reflect-config.json and friends under META-INF/native-image), which the native-image builder reads to preserve the listed types' reflective members.

saying these in an interview costs you the question

  • Thinking the annotation is needed on the JVM or affects normal JVM reflection
  • Believing native image supports reflection freely without any hints
  • Confusing reflection hints with resource or proxy hints

context

open as a page

How do you use @RegisterReflectionForBinding, and what do its 'classes' and 'classNames' attributes do?

level: middleimportance: should knowfreq 28%

basics

~20 s

Put @RegisterReflectionForBinding on a bean or config class and list the DTO types to keep for serialization. Use classes for types available at build time; use classNames (string names) for types you can't reference directly, e.g. package-private or not on the config's classpath.

open as a page

What is the difference between @RegisterReflection and @RegisterReflectionForBinding?

level: seniorimportance: should knowfreq 25%

basics

~20 s

@RegisterReflection is the general form: you pick exactly which member categories (constructors, fields, methods) to expose on the listed classes. @RegisterReflectionForBinding is a preset specialization that registers everything needed for serialization/deserialization and follows the type's property graph.

open as a page

When does Spring auto-detect binding types for native images, and when must you register them explicitly? What are the alternatives to @RegisterReflectionForBinding?

level: seniorimportance: should knowfreq 22%

basics

~20 s

Spring's AOT engine auto-detects DTOs it can see statically, like controller @RequestBody/@ResponseBody types. You register manually when Spring can't infer the type — e.g. bodies passed to RestClient/WebClient at runtime or resolved via generics. Alternatives: a RuntimeHintsRegistrar with @ImportRuntimeHints, or hand-written reflect-config.json.

open as a page

Explain how @RegisterReflectionForBinding is processed at AOT time — the @Reflective meta-annotation, ReflectiveProcessor, and BindingReflectionHintsRegistrar. What edge cases can still trip you up?

level: principalimportance: nice to knowfreq 14%

basics

~20 s

@RegisterReflectionForBinding is meta-annotated with @Reflective, which ties it to a ReflectiveProcessor that runs during Spring AOT. The processor uses BindingReflectionHintsRegistrar to register the serialization reflection for each listed type and recursively walk its property graph, emitting GraalVM reachability metadata.

open as a page