This is an automated email from the ASF dual-hosted git repository.

jamesfredley pushed a commit to branch bridge-backward-compat-shims
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit ea63dd26940dada566ca4aa9bd53043bb1e4b851
Author: James Fredley <[email protected]>
AuthorDate: Wed Mar 18 23:04:16 2026 -0400

    Harden bridge shims to fail fast instead of silently degrading
    
    Address review feedback to make deprecated bridge shims throw
    clear errors when misused, rather than silently creating duplicate
    instances or behaving differently from the new API.
    
    - GrailsApplicationPostProcessor: resolvePluginDiscovery() throws
      IllegalStateException if the discovery bean is not in the context
      instead of falling back to a new DefaultGrailsPluginDiscovery
    - GrailsApplicationPostProcessor: customizePluginManager() throws
      UnsupportedOperationException instead of being a silent no-op
    - DefaultGrailsPluginManager: deprecated constructors now fetch the
      existing discovery bean from GrailsApplication.getMainContext(),
      call reset()/init() to reinitialize, and log a warning instead
      of creating a new unmanaged DefaultGrailsPluginDiscovery instance
    - PluginFilterRetriever: getPluginFilter(Config) throws
      UnsupportedOperationException like CorePluginFinder, since
      Environment always has all configuration
    
    Assisted-by: Claude Code <[email protected]>
---
 .../config/GrailsApplicationPostProcessor.groovy   | 25 +++++---
 .../grails/plugins/DefaultGrailsPluginManager.java | 35 +++++++----
 .../org/grails/plugins/PluginFilterRetriever.java  | 68 ++++------------------
 3 files changed, 53 insertions(+), 75 deletions(-)

diff --git 
a/grails-core/src/main/groovy/grails/boot/config/GrailsApplicationPostProcessor.groovy
 
b/grails-core/src/main/groovy/grails/boot/config/GrailsApplicationPostProcessor.groovy
index 298ffc5bde..c33543da21 100644
--- 
a/grails-core/src/main/groovy/grails/boot/config/GrailsApplicationPostProcessor.groovy
+++ 
b/grails-core/src/main/groovy/grails/boot/config/GrailsApplicationPostProcessor.groovy
@@ -109,23 +109,34 @@ class GrailsApplicationPostProcessor implements 
BeanDefinitionRegistryPostProces
     }
 
     /**
-     * Resolves the {@link GrailsPluginDiscovery} from the application context 
if available,
-     * otherwise creates a new default instance. The bootstrap registry 
promotes the discovery
-     * bean before context refresh, so it is safe to look up by bean name at 
this stage.
+     * Resolves the {@link GrailsPluginDiscovery} from the application context.
+     * The bootstrap registry promotes the discovery bean before context 
refresh,
+     * so it is always available by bean name at this stage.
+     *
+     * @throws IllegalStateException if the application context is null or 
does not contain a GrailsPluginDiscovery bean
      */
     private static GrailsPluginDiscovery 
resolvePluginDiscovery(ApplicationContext applicationContext) {
-        if (applicationContext != null && 
applicationContext.containsBean(GrailsPluginDiscovery.BEAN_NAME)) {
-            return (GrailsPluginDiscovery) 
applicationContext.getBean(GrailsPluginDiscovery.BEAN_NAME)
+        if (applicationContext == null || 
!applicationContext.containsBean(GrailsPluginDiscovery.BEAN_NAME)) {
+            throw new IllegalStateException(
+                    'GrailsPluginDiscovery bean not found in 
ApplicationContext. ' +
+                    'Use 
GrailsApplicationPostProcessor(GrailsApplicationLifeCycle, ApplicationContext, 
GrailsPluginDiscovery, Class[]) instead.'
+            )
         }
-        return new 
org.apache.grails.core.plugins.DefaultGrailsPluginDiscovery()
+        return (GrailsPluginDiscovery) 
applicationContext.getBean(GrailsPluginDiscovery.BEAN_NAME)
     }
 
     /**
      * @deprecated Plugin manager customization is now handled through {@link 
org.apache.grails.core.plugins.GrailsPluginDiscovery}.
-     * This method is a no-op and will be removed in Grails 8.0.0.
+     * This method will be removed in Grails 8.0.0.
+     *
+     * @throws UnsupportedOperationException always - callers must switch to 
{@link org.apache.grails.core.plugins.GrailsPluginDiscovery}
      */
     @Deprecated(forRemoval = true, since = "7.1")
     protected void customizePluginManager(GrailsPluginManager pluginManager) {
+        throw new UnsupportedOperationException(
+                'customizePluginManager() is no longer supported. ' +
+                'Use org.apache.grails.core.plugins.GrailsPluginDiscovery to 
configure plugin discovery instead.'
+        )
     }
 
     protected final void initializeGrailsApplication(ApplicationContext 
applicationContext) {
diff --git 
a/grails-core/src/main/groovy/grails/plugins/DefaultGrailsPluginManager.java 
b/grails-core/src/main/groovy/grails/plugins/DefaultGrailsPluginManager.java
index 7dc2d3adec..8b467b92c9 100644
--- a/grails-core/src/main/groovy/grails/plugins/DefaultGrailsPluginManager.java
+++ b/grails-core/src/main/groovy/grails/plugins/DefaultGrailsPluginManager.java
@@ -41,7 +41,6 @@ import org.springframework.core.io.Resource;
 import grails.core.GrailsApplication;
 import grails.core.support.ParentApplicationContextAware;
 import grails.plugins.exceptions.PluginException;
-import org.apache.grails.core.plugins.DefaultGrailsPluginDiscovery;
 import org.apache.grails.core.plugins.GrailsPluginDescriptor;
 import org.apache.grails.core.plugins.GrailsPluginDiscovery;
 import org.apache.grails.core.plugins.GrailsPluginInfo;
@@ -96,32 +95,48 @@ public class DefaultGrailsPluginManager extends 
AbstractGrailsPluginManager {
 
     /**
      * @deprecated Use {@link #DefaultGrailsPluginManager(GrailsApplication, 
GrailsPluginDiscovery)} instead.
-     * Plugin discovery is now handled by {@link GrailsPluginDiscovery}. This 
constructor forwards
-     * the resource path to the discovery instance. Will be removed in Grails 
8.0.0.
+     * Plugin discovery is now handled by {@link GrailsPluginDiscovery}. This 
constructor fetches the
+     * existing discovery bean, resets and reinitializes it. Will be removed 
in Grails 8.0.0.
      */
     @Deprecated(forRemoval = true, since = "7.1")
     public DefaultGrailsPluginManager(String resourcePath, GrailsApplication 
application) {
-        this(application, new DefaultGrailsPluginDiscovery(resourcePath));
+        this(application, resolveAndReinitializeDiscovery(application));
     }
 
     /**
      * @deprecated Use {@link #DefaultGrailsPluginManager(GrailsApplication, 
GrailsPluginDiscovery)} instead.
-     * Plugin discovery is now handled by {@link GrailsPluginDiscovery}. This 
constructor forwards
-     * the plugin resources to the discovery instance. Will be removed in 
Grails 8.0.0.
+     * Plugin discovery is now handled by {@link GrailsPluginDiscovery}. This 
constructor fetches the
+     * existing discovery bean, resets and reinitializes it. Will be removed 
in Grails 8.0.0.
      */
     @Deprecated(forRemoval = true, since = "7.1")
     public DefaultGrailsPluginManager(String[] pluginResources, 
GrailsApplication application) {
-        this(application, new DefaultGrailsPluginDiscovery(pluginResources));
+        this(application, resolveAndReinitializeDiscovery(application));
     }
 
     /**
      * @deprecated Use {@link #DefaultGrailsPluginManager(GrailsApplication, 
GrailsPluginDiscovery)} instead.
-     * Plugin discovery is now handled by {@link GrailsPluginDiscovery}. This 
constructor forwards
-     * the plugin classes to the discovery instance. Will be removed in Grails 
8.0.0.
+     * Plugin discovery is now handled by {@link GrailsPluginDiscovery}. This 
constructor fetches the
+     * existing discovery bean, resets and reinitializes it. Will be removed 
in Grails 8.0.0.
      */
     @Deprecated(forRemoval = true, since = "7.1")
     public DefaultGrailsPluginManager(Class<?>[] plugins, GrailsApplication 
application) {
-        this(application, new DefaultGrailsPluginDiscovery(plugins));
+        this(application, resolveAndReinitializeDiscovery(application));
+    }
+
+    /**
+     * Resolves the {@link GrailsPluginDiscovery} bean from the application 
context,
+     * resets and reinitializes it. The GrailsApplication always has an 
application context
+     * set when these deprecated constructors are called.
+     */
+    private static GrailsPluginDiscovery 
resolveAndReinitializeDiscovery(GrailsApplication application) {
+        ApplicationContext ctx = application.getMainContext();
+        GrailsPluginDiscovery discovery = (GrailsPluginDiscovery) 
ctx.getBean(GrailsPluginDiscovery.BEAN_NAME);
+        LOG.warn("Using deprecated DefaultGrailsPluginManager constructor. " +
+                "Plugin discovery should be configured through the 
GrailsPluginDiscovery bean. " +
+                "Reinitializing plugin discovery.");
+        discovery.reset();
+        discovery.init(ctx.getEnvironment());
+        return discovery;
     }
 
     public GrailsPlugin[] getUserPlugins() {
diff --git 
a/grails-core/src/main/groovy/org/grails/plugins/PluginFilterRetriever.java 
b/grails-core/src/main/groovy/org/grails/plugins/PluginFilterRetriever.java
index fb09be4f2b..7d18a13ce3 100644
--- a/grails-core/src/main/groovy/org/grails/plugins/PluginFilterRetriever.java
+++ b/grails-core/src/main/groovy/org/grails/plugins/PluginFilterRetriever.java
@@ -18,76 +18,28 @@
  */
 package org.grails.plugins;
 
-import java.util.Collection;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import org.springframework.core.env.Environment;
-import org.springframework.util.StringUtils;
-
 import grails.config.Config;
-import grails.config.Settings;
 import grails.plugins.PluginFilter;
 
 /**
  * @deprecated Use {@link 
org.apache.grails.core.plugins.filters.PluginFilterRetriever} instead.
- * This compatibility bridge will be removed in Grails 8.0.0.
+ * This compatibility stub will be removed in Grails 8.0.0.
  */
 @Deprecated(forRemoval = true, since = "7.1")
 public class PluginFilterRetriever extends 
org.apache.grails.core.plugins.filters.PluginFilterRetriever {
 
-    /**
-     * @deprecated Use {@link 
org.apache.grails.core.plugins.filters.PluginFilterRetriever#getPluginFilter(Environment)}
 instead.
-     */
-    @Deprecated(forRemoval = true, since = "7.1")
-    public PluginFilter getPluginFilter(Config config) {
-        if (config == null) {
-            throw new IllegalArgumentException("Config should not be null");
-        }
-
-        if (config instanceof Environment environment) {
-            return super.getPluginFilter(environment);
-        }
-
-        Object includes = config.getProperty(Settings.PLUGIN_INCLUDES, 
Object.class, null);
-        Object excludes = config.getProperty(Settings.PLUGIN_EXCLUDES, 
Object.class, null);
-        return getPluginFilter(includes, excludes);
-    }
+    private static final String UNSUPPORTED_MESSAGE =
+            "PluginFilterRetriever.getPluginFilter(Config) is no longer 
supported. " +
+            "Use 
org.apache.grails.core.plugins.filters.PluginFilterRetriever.getPluginFilter(Environment)
 instead.";
 
     /**
-     * @deprecated Use {@link 
org.apache.grails.core.plugins.filters.PluginFilterRetriever#getPluginFilter(Environment)}
 instead.
+     * @deprecated Use {@link 
org.apache.grails.core.plugins.filters.PluginFilterRetriever#getPluginFilter(org.springframework.core.env.Environment)}
 instead.
+     * The Environment always has all configuration, so it is adaptable for 
all use cases.
+     *
+     * @throws UnsupportedOperationException always
      */
     @Deprecated(forRemoval = true, since = "7.1")
-    PluginFilter getPluginFilter(Object includes, Object excludes) {
-        if (includes != null) {
-            if (includes instanceof Collection<?> includesCollection) {
-                return new 
org.apache.grails.core.plugins.filters.IncludingPluginFilter(toSet(includesCollection));
-            }
-            return new 
org.apache.grails.core.plugins.filters.IncludingPluginFilter(StringUtils.commaDelimitedListToStringArray(includes.toString()));
-        }
-
-        if (excludes != null) {
-            if (excludes instanceof Collection<?> excludesCollection) {
-                return new 
org.apache.grails.core.plugins.filters.ExcludingPluginFilter(toSet(excludesCollection));
-            }
-            return new 
org.apache.grails.core.plugins.filters.ExcludingPluginFilter(StringUtils.commaDelimitedListToStringArray(excludes.toString()));
-        }
-
-        return new org.apache.grails.core.plugins.filters.NoOpPluginFilter();
-    }
-
-    private static Set<String> toSet(Collection<?> values) {
-        var set = new LinkedHashSet<String>();
-        for (Object v : values) {
-            if (v == null) {
-                continue;
-            }
-
-            String s = v.toString().trim();
-            if (!s.isEmpty()) {
-                set.add(s);
-            }
-        }
-        return set;
+    public PluginFilter getPluginFilter(Config config) {
+        throw new UnsupportedOperationException(UNSUPPORTED_MESSAGE);
     }
 }

Reply via email to