Beyond reflection, what do the resources, proxies, and serialization sub-registrars of RuntimeHints do, and when would you use each?
answer
- resources: registerPattern / registerResourceBundle
- proxies: registerJdkProxy(interfaces...)
- serialization: registerType (Java Serializable)
- Jackson JSON => reflection, not serialization
- Spring auto-covers @Transactional/@Async proxies
basics
~10 shints.resources() keeps classpath files/bundles you load by name; hints.proxies() declares JDK dynamic proxies for interfaces; hints.serialization() keeps types you (de)serialize with Java serialization. Use each when native analysis can't see that dynamic usage.
solid answer
~30 sRuntimeHints has four dynamic-feature sub-registrars beyond reflection. hints.resources().registerPattern("messages/*.properties") keeps classpath resources that you load by name (getResourceAsStream) — patterns aren't statically visible, so they'd be stripped; registerResourceBundle handles i18n bundles. hints.proxies().registerJdkProxy(MyInterface.class) declares a JDK dynamic proxy — GraalVM must generate the proxy class at build time, so you list the exact interface set; Spring already covers @Transactional/@Async proxies it detects, but a hand-rolled Proxy.newProxyInstance needs a hint. hints.serialization().registerType(MyDto.class) keeps a type usable with Java's Serializable mechanism. You use each when your code (or a library) triggers that dynamic behavior in a way Spring's automatic AOT contributions don't already detect.
code
java · 17 linesimport org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
public class DynamicFeatureHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader cl) {
// Resources loaded by name/pattern at runtime.
hints.resources().registerPattern("config/*.json");
hints.resources().registerResourceBundle("messages");
// A JDK dynamic proxy we create ourselves.
hints.proxies().registerJdkProxy(com.example.AuditPort.class);
// A type we persist via Java serialization.
hints.serialization().registerType(com.example.SessionData.class);
}
}go deeper
Should know there are more categories than reflection (resources, proxies).
Should map each sub-registrar to its dynamic feature and give a use case.
Should catch the Jackson-uses-reflection trap and know Spring auto-covers framework proxies.
Should reason about minimizing hint surface and which contributions Spring already provides vs. what the app must add.
`RuntimeHints` exposes four sub-registrars beyond `reflection()`, each mapping to a GraalVM dynamic-feature config. **1. Resources — `hints.resources()` (`ResourceHints`).** Native image only bundles classpath resources it's told about. If you load a file by name/pattern at runtime (`getResourceAsStream`, `ClassPathResource`, `@Value("classpath:...")` read dynamically), declare it: ```java hints.resources().registerPattern("config/*.json"); hints.resources().registerPattern("templates/email.html"); ``` Patterns use `*`/`**` globbing. For i18n: ```java hints.resources().registerResourceBundle("messages"); ``` Without this, the resource is absent in the binary and you get a null stream / missing-resource error. Note Spring Boot already registers many standard resources (e.g. `application.properties`), so only add non-standard ones. **2. Proxies — `hints.proxies()` (`ProxyHints`).** JDK dynamic proxies (`java.lang.reflect.Proxy`) are generated at runtime on the JVM, but native image must generate them at *build* time, so it needs the exact ordered set of interfaces: ```java hints.proxies().registerJdkProxy(MyService.class, org.springframework.aop.SpringProxy.class); ``` Spring's AOT already contributes proxies for framework features it detects — `@Transactional`, `@Async`, AOP advisors, `@ConfigurationProperties` interfaces, repository interfaces. You add hints only for proxies your own code creates via `Proxy.newProxyInstance`, or interface-based proxies a library doesn't self-declare. (CGLIB/class-based proxies are handled through reflection hints instead, and Spring's AOT prefers generating source over class proxies where it can.) **3. Serialization — `hints.serialization()` (`SerializationHints`).** For Java's built-in serialization (`Serializable`, `ObjectOutputStream`), the types must be registered: ```java hints.serialization().registerType(SessionData.class); ``` This is comparatively rare in modern apps (JSON via Jackson uses *reflection* hints, not serialization hints) — it matters for HTTP session persistence, RMI, or libraries using JDK serialization. **4. JNI — `hints.jni()`.** Rarely needed in typical Spring apps; declares types reachable via the Java Native Interface. **Choosing.** Ask what dynamic mechanism your code uses: reading a file by name → resources; `Proxy.newProxyInstance` on interfaces → proxies; `ObjectOutputStream`/`Serializable` → serialization; `Class.forName`/`Method.invoke`/field access → reflection. **Gotchas.** - Jackson JSON binding needs *reflection* hints (or `@RegisterReflectionForBinding`), not serialization hints — a very common mix-up. - Proxy interface order matters and must match exactly what the runtime requests. - Resource patterns are matched against the classpath; a typo silently yields no match and a runtime miss. - All four run at build time; none of this metadata is consulted on the JVM.
- You serialize a DTO to JSON with Jackson in a native image and it fails. Which sub-registrar fixes it?Reflection, not serialization. Jackson reads/writes via reflection over the type's fields/getters, so you need reflection hints (or the @RegisterReflectionForBinding convenience). SerializationHints is only for Java's Serializable/ObjectOutputStream mechanism.
- Do you need a proxy hint for a @Transactional service?Usually no — Spring's AOT processing already contributes the proxy/reflection metadata for framework-managed proxies like @Transactional and @Async. You add proxy hints for proxies your own code (or an unaware library) creates.
saying these in an interview costs you the question
- Using serialization hints for Jackson/JSON binding
- Thinking resource files are automatically bundled without a pattern
- Manually adding proxy hints for @Transactional (already covered)
- Ignoring that JDK proxy interface order/set must match exactly