You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Grails 8 now has a native-image build path: #16094 added processAot wiring, cooperation with org.graalvm.buildtools.native, and the GenerateNativeMetadataTask / TraceNativeMetadataTask machinery, and #16102 moved i18n onto Spring Boot's MessageSource with an I18nRuntimeHintsProcessor that registers resource hints for the effective spring.messages.basename.
What neither PR established is a build that actually compiles a native binary and runs it. Today:
nothing in the repository invokes nativeCompile, nativeRun or nativeTest;
no CI workflow provisions GraalVM or mentions native-image;
grails-test-examples/aot verifies processAot output and a JVM startup check, both of which run on a normal JDK.
So every native-image claim in the framework currently rests on JVM-level AOT processing plus reasoning about the metadata, rather than on a binary that was built and exercised. That is a reasonable place to have landed the feature work, but it leaves a gap worth closing deliberately.
Proposal
Add a native-image verification target — most likely under end-to-end/, since it already consumes published artifacts — that builds a real GraalVM binary from a Grails application and asserts runtime behaviour that only a native image can falsify.
Suggested first assertions, ordered by how likely they are to catch something:
Plugin message bundles resolve. A namespaced plugin bundle (for example spring-security-core_fr.properties) resolving in the binary. This is the case Spring Boot's own MessageSourceRuntimeHints does not cover — it registers two hardcoded messages* patterns and derives nothing from the configured base names — so if I18nRuntimeHintsProcessor is wrong, plugin messages resolve on the JVM and silently vanish in native.
A base name the application configured itself resolves, e.g. spring.messages.basename: config/i18n/custom, covering the dot-to-slash path conversion.
The i18n descriptor is readable, since base-name discovery reads META-INF/grails/i18n.properties through an exact-name ClassLoader.getResources lookup at runtime.
I18nRuntimeHintsProcessor uses the same hint API Spring Boot uses. Boot's MessageSourceRuntimeHints calls registerPattern (verified in spring-boot-autoconfigure 4.1.0: it references registerPattern, messages.properties and messages_*.properties, and never registerResourceBundle), and this processor does the same. The difference is coverage, not mechanism: Boot registers two hardcoded messages* patterns and derives nothing from the configured base names, whereas this one generates patterns from the effective spring.messages.basename, which is what brings namespaced plugin bundles along.
The open question is only whether the more precise hints.resources().registerResourceBundle(...) would also work. It exists and is the more obvious API for message bundles, yet Boot does not use it. The likely reason is that it serialises to a {"bundle": ...} entry, which GraalVM resolves against the image's included locale set, so non-default locales could drop out — but that is inferred from reading the serialisation code, not documented by Boot or confirmed against a binary. A native test would settle it. If registerResourceBundle turns out to be safe, the hints could become more precise.
Notes
This is framework-wide infrastructure, not specific to i18n: a native job would serve the AOT cache work, GORM, GSP and anything else that ships hints.
Cost is the main design question. A full nativeCompile is minutes of CPU and needs a GraalVM toolchain, so it probably belongs on a scheduled or opt-in workflow rather than every PR.
Background
Grails 8 now has a native-image build path: #16094 added
processAotwiring, cooperation withorg.graalvm.buildtools.native, and theGenerateNativeMetadataTask/TraceNativeMetadataTaskmachinery, and #16102 moved i18n onto Spring Boot'sMessageSourcewith anI18nRuntimeHintsProcessorthat registers resource hints for the effectivespring.messages.basename.What neither PR established is a build that actually compiles a native binary and runs it. Today:
nativeCompile,nativeRunornativeTest;grails-test-examples/aotverifiesprocessAotoutput and a JVM startup check, both of which run on a normal JDK.So every native-image claim in the framework currently rests on JVM-level AOT processing plus reasoning about the metadata, rather than on a binary that was built and exercised. That is a reasonable place to have landed the feature work, but it leaves a gap worth closing deliberately.
Proposal
Add a native-image verification target — most likely under
end-to-end/, since it already consumes published artifacts — that builds a real GraalVM binary from a Grails application and asserts runtime behaviour that only a native image can falsify.Suggested first assertions, ordered by how likely they are to catch something:
spring-security-core_fr.properties) resolving in the binary. This is the case Spring Boot's ownMessageSourceRuntimeHintsdoes not cover — it registers two hardcodedmessages*patterns and derives nothing from the configured base names — so ifI18nRuntimeHintsProcessoris wrong, plugin messages resolve on the JVM and silently vanish in native.spring.messages.basename: config/i18n/custom, covering the dot-to-slash path conversion.META-INF/grails/i18n.propertiesthrough an exact-nameClassLoader.getResourceslookup at runtime.Open question worth settling with the test
I18nRuntimeHintsProcessoruses the same hint API Spring Boot uses. Boot'sMessageSourceRuntimeHintscallsregisterPattern(verified inspring-boot-autoconfigure4.1.0: it referencesregisterPattern,messages.propertiesandmessages_*.properties, and neverregisterResourceBundle), and this processor does the same. The difference is coverage, not mechanism: Boot registers two hardcodedmessages*patterns and derives nothing from the configured base names, whereas this one generates patterns from the effectivespring.messages.basename, which is what brings namespaced plugin bundles along.The open question is only whether the more precise
hints.resources().registerResourceBundle(...)would also work. It exists and is the more obvious API for message bundles, yet Boot does not use it. The likely reason is that it serialises to a{"bundle": ...}entry, which GraalVM resolves against the image's included locale set, so non-default locales could drop out — but that is inferred from reading the serialisation code, not documented by Boot or confirmed against a binary. A native test would settle it. IfregisterResourceBundleturns out to be safe, the hints could become more precise.Notes
nativeCompileis minutes of CPU and needs a GraalVM toolchain, so it probably belongs on a scheduled or opt-in workflow rather than every PR.Raised from review discussion on #16102.