skip to content

Beyond reflection, what other hint categories can RuntimeHintsPredicates assert, and how?

level: middleimportance: should knowfreq 30%

answer

  1. reflection / resource / proxies / serialization
  2. resource().forResource vs forBundle
  3. proxies().forInterfaces = exact ordered set
  4. serialization().onType
  5. Spring proxy marker interfaces gotcha

basics

~10 s

It also covers resources, JDK proxies, and serialization: resource().forResource("...") and resource().forBundle("messages"), proxies().forInterfaces(A.class, B.class), and serialization().onType(X.class) — each returns a Predicate<RuntimeHints> you assert with AssertJ.

solid answer

~30 s

`RuntimeHintsPredicates` exposes one entry point per hint type. `reflection()` for reflective member access; `resource()` with `.forResource("config/app.properties")` for classpath resource patterns and `.forBundle("messages")` for `ResourceBundle`s; `proxies()` with `.forInterfaces(MyInterface.class, ...)` to assert a JDK dynamic proxy hint for an exact interface list; and `serialization()` with `.onType(MySerializable.class)` for Java serialization. Each returns a `Predicate<RuntimeHints>` you assert via AssertJ `accepts`/`rejects`. The proxy predicate is order- and set-sensitive: `forInterfaces(A, B)` matches only a proxy hint registered for exactly that interface set. These mirror the four sub-registrars on `RuntimeHints`: `reflection()`, `resources()`, `proxies()`, `serialization()`.

code

java · 19 lines
java
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import static org.assertj.core.api.Assertions.assertThat;

RuntimeHints hints = new RuntimeHints();
new MyHints().registerHints(hints, getClass().getClassLoader());

// resource
assertThat(RuntimeHintsPredicates.resource()
        .forResource("config/app.properties")).accepts(hints);
// resource bundle (i18n)
assertThat(RuntimeHintsPredicates.resource()
        .forBundle("messages")).accepts(hints);
// JDK proxy over an exact interface set
assertThat(RuntimeHintsPredicates.proxies()
        .forInterfaces(MyRepository.class)).accepts(hints);
// serialization
assertThat(RuntimeHintsPredicates.serialization()
        .onType(MyEvent.class)).accepts(hints);

go deeper

for a junior

Knows more than reflection exists — resources, proxies, serialization.

for a middle

Can write assertions across all four families and knows forResource vs forBundle.

for a senior

Understands proxy exact-set matching and Spring marker interfaces; uses negative assertions deliberately.

for a principal

Guides which categories a library must test and reviews for over-registration footprint.

## The four hint families `RuntimeHints` groups hints into sub-registrars, and `RuntimeHintsPredicates` provides a matching predicate factory for each: | RuntimeHints registrar | Predicate factory | What it declares for native | |---|---|---| | `reflection()` | `RuntimeHintsPredicates.reflection()` | Reflective access to types/methods/fields/constructors | | `resources()` | `RuntimeHintsPredicates.resource()` | Non-class classpath resources + resource bundles | | `proxies()` | `RuntimeHintsPredicates.proxies()` | JDK dynamic proxies over an interface set | | `serialization()` | `RuntimeHintsPredicates.serialization()` | Java (`Serializable`) serialization | ## Resource predicates ```java assertThat(RuntimeHintsPredicates.resource() .forResource("config/app.properties")).accepts(hints); assertThat(RuntimeHintsPredicates.resource() .forBundle("messages")).accepts(hints); ``` `forResource(String)` asserts a resource pattern hint covers that path; `forBundle(String)` asserts a `ResourceBundle` base name was registered (important for i18n `messages.properties` in native images). ## Proxy predicates — set-sensitive ```java assertThat(RuntimeHintsPredicates.proxies() .forInterfaces(MyRepository.class, Serializable.class)) .accepts(hints); ``` JDK dynamic proxies are defined by the **exact, ordered list of interfaces**. `forInterfaces(A, B)` will **not** accept a hint registered for `forInterfaces(A)` or `forInterfaces(B, A)`. This trips people up: Spring often adds marker interfaces (e.g. `SpringProxy`, `Advised`, `DecoratingProxy`) to AOP proxies, so a naive `forInterfaces(MyService.class)` may reject. Assert the full interface list the proxy is actually registered with. ## Serialization predicates ```java assertThat(RuntimeHintsPredicates.serialization() .onType(MyEvent.class)).accepts(hints); ``` Use when a type crosses a boundary via Java serialization (e.g. session replication, RMI-style flows) and must be serialization-enabled in the native binary. ## Choosing accepts vs rejects Across all families, `.accepts(hints)` proves the hint exists, `.rejects(hints)` proves it doesn't. Negative assertions matter for security/footprint: e.g. assert an internal DTO is **not** proxied or serialized. ## Gotcha summary - Reflection: subset/contains-at-least matching on member categories. - Resource: `forResource` is a path/pattern, `forBundle` is a bundle base name — don't confuse them. - Proxies: exact ordered interface set; include Spring's marker interfaces. - Serialization: type-level, straightforward.

  • Why might proxies().forInterfaces(MyService.class) reject a real Spring AOP proxy hint?
    Spring registers the proxy with extra marker interfaces (e.g. SpringProxy, Advised, DecoratingProxy). The predicate needs the exact, complete interface list, so a single-interface assertion won't match.

context