Skip to content

Honor EnvironmentAware application classes before early plugin registration#15979

Draft
codeconsole wants to merge 1 commit into
apache:8.0.xfrom
codeconsole:feat/early-phase-environment-aware
Draft

Honor EnvironmentAware application classes before early plugin registration#15979
codeconsole wants to merge 1 commit into
apache:8.0.xfrom
codeconsole:feat/early-phase-environment-aware

Conversation

@codeconsole

Copy link
Copy Markdown
Contributor

Problem

#15934 retimed plugin doWithSpring to run before Spring Boot auto-configuration — and therefore before any bean is created. An application class using the long-documented externalized-configuration pattern:

class Application extends GrailsAutoConfiguration implements EnvironmentAware {
    void setEnvironment(Environment environment) {
        // fetch secrets / discover endpoints, addFirst a property source
    }
}

previously had setEnvironment invoked (when the application configuration bean was instantiated) before plugin bean registration ran. After the retiming, plugins that resolve settings inside doWithSpring read configuration the application has not customized yet. The GORM plugins resolve their connection URLs there — e.g. MongodbGrailsPlugin.doWithSpring() builds MongoDbDataStoreSpringInitializer from config at definition time — so an app that injects its production MongoDB URL from a secret manager in setEnvironment silently boots against the static yaml default (localhost) instead. Beans that read the Environment at creation time (Redis, Elasticsearch, @Value) are unaffected, which makes the failure look like a Mongo-specific mystery. This is a real-world regression observed in production on the re-staged 8.0.0-M3.

Fix

Replay the contract at the start of GrailsEarlyPluginRegistrationPostProcessor: for each stashed application source class that is a GrailsAutoConfiguration/GrailsApplicationClass and implements EnvironmentAware, invoke setEnvironment on a detached instance — the same approach the phase already uses for artefact scanning (scanApplicationSource) — before plugin loading, the PropertySourcesConfig snapshot, and the doWithSpring drain.

The real application bean still receives the standard EnvironmentAware callback when Spring creates it later, so implementations must be idempotent: contribute a named property source (re-adding a source with the same name replaces the earlier one) rather than accumulate state. This is documented on the new method and asserted in the spec (INVOCATIONS == 2, no duplicated source).

Testing

New test in EarlyPluginRegistrationOrderingSpec: a plugin that reads config in doWithSpring (as the GORM plugins do) observes the value contributed by the application's setEnvironment, not the default; the double-callback semantics are pinned. Full :grails-core:test and checkstyle pass.

Happy to add an upgrade-notes entry in grails-doc ("setEnvironment on EnvironmentAware application classes now runs twice; keep it idempotent") if wanted.

…ration

The retimed plugin lifecycle (apache#15934) drains plugin doWithSpring before
any bean is created, so an application class using the documented
externalized-configuration pattern — implementing EnvironmentAware and
contributing property sources from setEnvironment — no longer runs
before plugins read configuration. Plugins that resolve settings inside
doWithSpring (the GORM plugins resolve their connection URLs there)
silently fall back to the static yaml values: a Grails 7 app that
injected its production MongoDB URL from a secret manager boots against
the localhost default on 8.0.

Replay the contract at the start of the early phase: for each stashed
application source class that is a GrailsAutoConfiguration or
GrailsApplicationClass and implements EnvironmentAware, invoke
setEnvironment on a detached instance (the same approach the phase
already uses for artefact scanning) before plugin loading, the config
snapshot, and the doWithSpring drain. The real application bean still
receives the standard callback when Spring creates it later, so
implementations must stay idempotent — contribute a named property
source, which replaces rather than accumulates.
@codeconsole codeconsole marked this pull request as draft July 13, 2026 15:20
@testlens-app

testlens-app Bot commented Jul 13, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: a5a0b5f
▶️ Tests: 55170 executed
⚪️ Checks: 59/59 completed


Learn more about TestLens at testlens.app.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant