Skip to content

Load plugin.yml/plugin.groovy earlier so @Conditional* annotations can be used#15409

Open
jdaugherty wants to merge 42 commits intoapache:7.1.xfrom
jdaugherty:conditionalPluginConfiguration
Open

Load plugin.yml/plugin.groovy earlier so @Conditional* annotations can be used#15409
jdaugherty wants to merge 42 commits intoapache:7.1.xfrom
jdaugherty:conditionalPluginConfiguration

Conversation

@jdaugherty
Copy link
Contributor

Fixes #15408

Assisted-by: OpenCode <opencode@opencode.ai>
Assisted-by: Claude <claude@anthropic.com>

@jdaugherty jdaugherty force-pushed the conditionalPluginConfiguration branch from 1232204 to e109334 Compare February 18, 2026 16:53
@jdaugherty jdaugherty marked this pull request as draft February 18, 2026 16:57
@jdaugherty jdaugherty force-pushed the conditionalPluginConfiguration branch from 46f5e8f to 9f81969 Compare February 18, 2026 17:17
@bito-code-review
Copy link

You're right—deprecation annotations should include a reason for clarity. For this method, the reason could be that plugin property sources are now handled early by GrailsPluginEnvironmentPostProcessor.

@jamesfredley
Copy link
Contributor

If this does not require changes in end Grails apps I am OK with this going into 7.0.x, if we think the risk is too high, then 7.1.x is also OK.

Copy link
Contributor

@jamesfredley jamesfredley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks solid. A few minor items to take a look at.

The GrailsPluginConfigurationClass test removed the "plugin with both yml and groovy throws exception" test. That validation still exists in GrailsPluginEnvironmentPostProcessor.readPluginConfiguration() (line 293), but there's no unit test covering it in the new code. The GrailsPluginEnvironmentPostProcessorSpec should add a test for this.

@jdaugherty jdaugherty force-pushed the conditionalPluginConfiguration branch from 462035b to ee32e61 Compare February 28, 2026 02:42
@jdaugherty jdaugherty changed the base branch from 7.0.x to 7.1.x March 1, 2026 05:35
@jdaugherty
Copy link
Contributor Author

This change is incomplete since the plugin configuration will be loaded potentially when the plugin is disabled. We may be able to post process already loaded configuration and remove them, but I'm not sure without further research.

Here's the loading order in Spring:

• SpringApplication.run(...)
• Prepare SpringApplicationRunListeners
• Prepare Environment
Create/attach ConfigurableEnvironment
Invoke all EnvironmentPostProcessors
• Create ApplicationContext
• Prepare context
• Refresh context (bean creation begins)

The problem is the plugin manager has different discovery mechanisms (but very similar). Worst, one of those mechanisms appears to require the application context, which won't exist when we need to load configuration. I think the need for the application context (or rather the parent application context) isn't actually used though.

I'm doing further research on this to see how best to unify the plugin manager mechanisms so we can share the logic in both places.

@jdaugherty
Copy link
Contributor Author

jdaugherty commented Mar 1, 2026

I've been working on this and will likely push a significant update in the next day or so. The core issue is the plugin filtering needs shared between the environment & the application post processors. The problem: the plugin manager is what currently does this filtering & it's a bean. The environment post processor can't use a bean b/c the context doesn't exist yet. The only practical place the filtering is used is when in unit tests it filters the plugins. I think the right solution is either moving the filter further out & sharing it between the plugin manager / EPP, or just moving the plugin manager away from being a bean completely.

@jdaugherty jdaugherty force-pushed the conditionalPluginConfiguration branch 2 times, most recently from 406aa4a to d7175cf Compare March 2, 2026 00:16
@jdaugherty jdaugherty force-pushed the conditionalPluginConfiguration branch from d7175cf to 13ec1b0 Compare March 3, 2026 20:00
@matrei
Copy link
Contributor

matrei commented Mar 12, 2026

@jdaugherty Why did you choose to write new classes in Java, and not Groovy?

Copy link
Contributor

@matrei matrei left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a great effort @jdaugherty, thank you!

As changes a some of the public API of core functionality, I think it would be wise to target 8.0.x.


/**
* Returns the location of the Resource that represents the plugin descriptor (the *GrailsPlugin.groovy file)
* Returns the location of the Resource that represents the plugin descriptor (the *GrailsPlugin.groovy or grails-plugin.yml file)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't the grails-plugin.yml created from the *GrailsPlugin.groovy file so this is essentially the same thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are 2 code paths - binary plugins load from grails-plugin.yml & source based plugins load from GrailsPlugin. Source based plugins that are loaded dynamically do not have a grails-plugin.yml. I think this really exists today for tests only. I was trying to call out these 2 code paths in this comment.

* @return the plugin's property source from the environment, or {@code null} if the
* GrailsApplication main context is not yet available or no matching property source exists
*/
@Deprecated(forRemoval = true)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why Java (general question for all new classes)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The classes in this area have historically been java. Looking through the commit history, there have been numerous performance problems in this area and conversion to java was one of the "fixes". I did not want to introduce a new pattern as I was only trying to abstract the existing logic. I think if we introduce a hard contract, we could change this with some significant refactoring.

@jdaugherty jdaugherty force-pushed the conditionalPluginConfiguration branch from a7cd577 to c8e65a8 Compare March 12, 2026 17:32
@jdaugherty jdaugherty force-pushed the conditionalPluginConfiguration branch from c8e65a8 to 11cbf53 Compare March 12, 2026 17:34
@jdaugherty
Copy link
Contributor Author

This was a great effort @jdaugherty, thank you!

As changes a some of the public API of core functionality, I think it would be wise to target 8.0.x.

The problem I have with 8.0 is:

  1. this works with all of the plugins in my current application with no breakage (that I can tell).
  2. a core piece of Spring 3.x is broken currently without this change
  3. there is a precedent of us already committing breaking changes to 7.1.
  4. we can do a milestone to see if there's impact and then revert if there is?

@jamesfredley
Copy link
Contributor

A potential start on backward-compatibility bridge shims for 7.1.x:
jdaugherty#5

@matrei
Copy link
Contributor

matrei commented Mar 13, 2026

The problem I have with 8.0 is:

This is excellent, but is it relevant?

1. this works with all of the plugins in my current application with no breakage (that I can tell).

@ConditionalOnProperty was introduced in Spring Boot 1.1

2. a core piece of Spring 3.x is broken currently without this change

Yeah, but not in this way, and that was a hard call.

3. there is a precedent of us already committing breaking changes to 7.1.

Unfortunately, not many projects try out milestones.

4. we can do a milestone to see if there's impact and then revert if there is?

If we can get the API backwards compatible, I have no problem including this in 7.1. I see that @jamesfredley already started this work in jdaugherty#5.

@jamesfredley
Copy link
Contributor

I plan to approve this once the backward-compatibility bridge shims are in place for 7.1.x. Thank you @jdaugherty

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.

Plugin configuration is loaded after @Conditional checks in Spring

4 participants