skip to content

What is the ReflectiveProcessor interface, and what does the default SimpleReflectiveProcessor register?

level: middleimportance: should knowfreq 15%

answer

  1. one method: registerReflectionHints(hints, element)
  2. AnnotatedElement = Class/Method/Constructor/Field
  3. SimpleReflectiveProcessor branches on element type
  4. executables registered with ExecutableMode.INVOKE
  5. narrow by design — only the annotated member

basics

~10 s

ReflectiveProcessor is an interface with one method, registerReflectionHints(ReflectionHints, AnnotatedElement), that decides which hints to emit. SimpleReflectiveProcessor is the default: it registers the type, or the specific constructor/method for reflective invocation.

solid answer

~40 s

ReflectiveProcessor (org.springframework.aot.hint.annotation) is the strategy that a @Reflective-annotated annotation binds to. Its single method, registerReflectionHints(ReflectionHints hints, AnnotatedElement element), receives the annotated element — a Class, Constructor, Method, or Field — and writes entries into ReflectionHints. The default, SimpleReflectiveProcessor, branches on the element type: for a Class it registers the type itself; for a Constructor or Method it registers it with ExecutableMode.INVOKE so it can be called reflectively; for a Field it registers the field. It deliberately registers narrowly — just enough to reflect on the exact annotated member — rather than opening up the whole type. If you need broader access (all fields, all constructors) or to walk a type graph, you supply a custom ReflectiveProcessor via @Reflective's value attribute.

code

java · 16 lines
java
// Simplified view of the default processor's dispatch logic
public class SimpleReflectiveProcessor implements ReflectiveProcessor {
    @Override
    public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) {
        if (element instanceof Class<?> type) {
            registerTypeHint(hints, type);           // hints.registerType(type)
        } else if (element instanceof Constructor<?> ctor) {
            registerConstructorHint(hints, ctor);    // INVOKE
        } else if (element instanceof Field field) {
            registerFieldHint(hints, field);
        } else if (element instanceof Method method) {
            registerMethodHint(hints, method);       // INVOKE
        }
    }
    // protected methods are overridable to broaden the hints
}

go deeper

for a junior

Know the default processor exists and emits hints for the annotated element.

for a middle

Describe the single-method interface and SimpleReflectiveProcessor's per-element-type behaviour.

for a senior

Explain ExecutableMode.INVOKE vs INTROSPECT and why the default is deliberately narrow.

for a principal

Reason about metadata size trade-offs and when to override protected hooks vs write a fresh processor.

## The interface ```java package org.springframework.aot.hint.annotation; @FunctionalInterface public interface ReflectiveProcessor { void registerReflectionHints(ReflectionHints hints, AnnotatedElement element); } ``` - **`ReflectionHints`** (`org.springframework.aot.hint`) is the mutable collection of reflection metadata being built during AOT. You call methods like `registerType(...)`, `registerMethod(...)`, `registerConstructor(...)`, `registerField(...)` on it. - **`AnnotatedElement`** is the JDK reflection abstraction implemented by `Class`, `Method`, `Constructor`, and `Field` — i.e. whatever element carried the `@Reflective`-meta-annotated annotation. A `ReflectiveProcessor` is therefore a **strategy**: given the element that triggered scanning, decide precisely which hints to emit. ## SimpleReflectiveProcessor — the default When `@Reflective` names no processor, `SimpleReflectiveProcessor` is used. Its logic: - **`Class`** → `hints.registerType(type)` (registers the type for reflection; by default this makes the type known/introspectable without necessarily opening all members). - **`Constructor`** → `hints.registerConstructor(constructor, ExecutableMode.INVOKE)` so it can be **invoked** reflectively (e.g. `newInstance`). - **`Method`** → `hints.registerMethod(method, ExecutableMode.INVOKE)` so it can be invoked reflectively. - **`Field`** → `hints.registerField(field)`. **`ExecutableMode`** has two values: `INTROSPECT` (you can look the executable up / read its metadata) and `INVOKE` (you can also call it). `SimpleReflectiveProcessor` uses `INVOKE` for executables so the annotated method/constructor is actually callable. Key point: it is **surgical** — it registers only the exact annotated member, not the entire declaring type's members. That keeps the generated metadata (and native image size) minimal. ## When to subclass vs replace `SimpleReflectiveProcessor`'s per-element methods (`registerTypeHint`, `registerMethodHint`, etc.) are `protected`, so you can extend it and override just one branch — e.g. register a whole class's declared fields when the annotation lands on a type. Or implement `ReflectiveProcessor` from scratch for arbitrary logic. ## Gotchas - The method is called **once per matching element**, at build time. - Registering a type alone does not automatically register its members for invocation — for serialization you need member categories (that's what `BindingReflectionHintsRegistrar` / `@RegisterReflectionForBinding` add). - Because it's a `@FunctionalInterface`, a processor can be a lambda, but real ones are usually classes so `@Reflective(MyProcessor.class)` can name them.

  • What is the difference between ExecutableMode.INTROSPECT and ExecutableMode.INVOKE?
    INTROSPECT lets you discover/look up the constructor or method and read its metadata; INVOKE additionally allows actually calling it reflectively. SimpleReflectiveProcessor uses INVOKE for annotated executables.

saying these in an interview costs you the question

  • Claiming SimpleReflectiveProcessor opens up all members of the declaring class.
  • Saying ReflectiveProcessor runs at application startup rather than AOT build time.
  • Confusing registering a type with registering its methods for invocation.

context