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

matrei pushed a commit to branch refactor-global-injector-trans
in repository https://gitbox.apache.org/repos/asf/grails-core.git


The following commit(s) were added to refs/heads/refactor-global-injector-trans 
by this push:
     new cdad075730 refactor: make pending lists an internal instance concern
cdad075730 is described below

commit cdad075730393e20915ec5378feb2e820940d088
Author: Mattias Reichel <[email protected]>
AuthorDate: Tue Jul 28 14:38:42 2026 +0200

    refactor: make pending lists an internal instance concern
---
 .../GlobalGrailsClassInjectorTransformation.groovy | 21 +++---
 ...balGrailsClassInjectorTransformationSpec.groovy | 83 +++++++---------------
 2 files changed, 35 insertions(+), 69 deletions(-)

diff --git 
a/grails-core/src/main/groovy/org/grails/compiler/injection/GlobalGrailsClassInjectorTransformation.groovy
 
b/grails-core/src/main/groovy/org/grails/compiler/injection/GlobalGrailsClassInjectorTransformation.groovy
index 176ce7daea..e347680de5 100644
--- 
a/grails-core/src/main/groovy/org/grails/compiler/injection/GlobalGrailsClassInjectorTransformation.groovy
+++ 
b/grails-core/src/main/groovy/org/grails/compiler/injection/GlobalGrailsClassInjectorTransformation.groovy
@@ -37,16 +37,13 @@ import org.codehaus.groovy.ast.ClassNode
 import org.codehaus.groovy.ast.PropertyNode
 import org.codehaus.groovy.ast.expr.ConstantExpression
 import org.codehaus.groovy.control.CompilationUnit
-import org.codehaus.groovy.control.CompilePhase
 import org.codehaus.groovy.control.SourceUnit
-import org.codehaus.groovy.runtime.InvokerHelper
 import org.codehaus.groovy.transform.ASTTransformation
 import org.codehaus.groovy.transform.GroovyASTTransformation
 import org.codehaus.groovy.transform.TransformWithPriority
 
-import org.xml.sax.SAXException
-
 import org.jspecify.annotations.Nullable
+import org.xml.sax.SAXException
 
 import grails.artefact.Artefact
 import grails.compiler.ast.ClassInjector
@@ -73,7 +70,7 @@ import org.grails.io.support.UrlResource
  */
 @Slf4j
 @CompileStatic
-@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
+@GroovyASTTransformation
 class GlobalGrailsClassInjectorTransformation implements ASTTransformation, 
CompilationUnitAware, TransformWithPriority {
 
     /**
@@ -87,8 +84,8 @@ class GlobalGrailsClassInjectorTransformation implements 
ASTTransformation, Comp
     public static final ClassNode ARTEFACT_HANDLER_CLASS = 
ClassHelper.make('grails.core.ArtefactHandler')
     public static final ClassNode TRAIT_INJECTOR_CLASS = 
ClassHelper.make('grails.compiler.traits.TraitInjector')
 
-    static LinkedHashSet<String> pendingPluginClassNames = []
-    static Collection<String> pluginExcludePatterns = []
+    private final LinkedHashSet<String> pendingPluginClassNames = []
+    private final Collection<String> pluginExcludePatterns = []
 
     CompilationUnit compilationUnit
 
@@ -270,7 +267,7 @@ class GlobalGrailsClassInjectorTransformation implements 
ASTTransformation, Comp
      * @param transformedClassNames the artefact classes transformed in the 
current source unit
      * @param pluginXmlFile the generated plugin descriptor file
      */
-    protected static void generatePluginXml(
+    protected void generatePluginXml(
             @Nullable ClassNode pluginClassNode,
             @Nullable String pluginVersion,
             Set<String> transformedClassNames,
@@ -317,7 +314,7 @@ class GlobalGrailsClassInjectorTransformation implements 
ASTTransformation, Comp
      * @param artefactClassNames artefact class names to include as resources
      */
     @CompileDynamic
-    static void writePluginXml(
+    void writePluginXml(
             @Nullable ClassNode pluginClassNode,
             String pluginVersion,
             File pluginXml,
@@ -384,7 +381,7 @@ class GlobalGrailsClassInjectorTransformation implements 
ASTTransformation, Comp
      * @param pluginXmlFile the existing plugin descriptor file
      * @param artefactClassNames artefact class names to add as resources
      */
-    static void updatePluginXml(
+    void updatePluginXml(
             @Nullable ClassNode pluginClassNode,
             @Nullable String pluginVersion,
             File pluginXmlFile,
@@ -423,7 +420,7 @@ class GlobalGrailsClassInjectorTransformation implements 
ASTTransformation, Comp
      * @param pluginXml the parsed plugin descriptor
      */
     @CompileDynamic
-    protected static void handleExcludes(GPathResult pluginXml) {
+    protected void handleExcludes(GPathResult pluginXml) {
         if (pluginExcludePatterns) {
             pluginXml.resources.resource.each { resourceNode ->
                 if (isResourceExcludedByPlugin((resourceNode as 
GPathResult).text())) {
@@ -439,7 +436,7 @@ class GlobalGrailsClassInjectorTransformation implements 
ASTTransformation, Comp
      * @param resourceName the resource name to test
      * @return {@code true} when the resource should be excluded
      */
-    private static boolean isResourceExcludedByPlugin(String resourceName) {
+    private boolean isResourceExcludedByPlugin(String resourceName) {
         def matcher = new AntPathMatcher()
         def resourcePath = resourceName.replace('.', '/')
         pluginExcludePatterns.any {
diff --git 
a/grails-core/src/test/groovy/org/grails/compiler/injection/GlobalGrailsClassInjectorTransformationSpec.groovy
 
b/grails-core/src/test/groovy/org/grails/compiler/injection/GlobalGrailsClassInjectorTransformationSpec.groovy
index 72717aaa05..afc2bc0bf1 100644
--- 
a/grails-core/src/test/groovy/org/grails/compiler/injection/GlobalGrailsClassInjectorTransformationSpec.groovy
+++ 
b/grails-core/src/test/groovy/org/grails/compiler/injection/GlobalGrailsClassInjectorTransformationSpec.groovy
@@ -37,7 +37,9 @@ import ch.qos.logback.classic.Logger
 import ch.qos.logback.classic.spi.ILoggingEvent
 import ch.qos.logback.core.read.ListAppender
 import org.slf4j.LoggerFactory
+import spock.lang.Shared
 import spock.lang.Specification
+import spock.lang.Subject
 import spock.lang.TempDir
 import spock.util.environment.RestoreSystemProperties
 
@@ -51,31 +53,21 @@ class GlobalGrailsClassInjectorTransformationSpec extends 
Specification {
     @TempDir
     File tempDir
 
-    def cleanup() {
-        GlobalGrailsClassInjectorTransformation.pendingPluginClassNames.clear()
-        GlobalGrailsClassInjectorTransformation.pluginExcludePatterns.clear()
-    }
+    @Subject
+    def transformation = new GlobalGrailsClassInjectorTransformation()
 
     void "a correct plugin xml file is generated when the plugin xml doesn't 
exist"() {
         given: "a file that doesn't yet exist"
             def pluginXml = new File(tempDir, 'plugin-xml-gen-test.test.xml')
 
         and: "the class node for a plugin descriptor"
-            def classNode = null
-            def cu = new CompilationUnit(new GroovyClassLoader())
-            cu.addSource('FooGrailsPlugin', 'class FooGrailsPlugin {}')
-            cu.addPhaseOperation({ SourceUnit source, GeneratorContext 
context, ClassNode cn ->
-                if (cn.name.endsWith('GrailsPlugin')) {
-                     classNode = cn
-                }
-            } as CompilationUnit.IPrimaryClassNodeOperation, Phases.CONVERSION)
-            cu.compile(Phases.CONVERSION)
+            def classNode = compilePlugin('class FooGrailsPlugin {}')
 
         expect: "the file doesn't exist"
             !pluginXml.exists()
 
         when: "the transformation generates the xml file"
-            GlobalGrailsClassInjectorTransformation.generatePluginXml(
+            transformation.generatePluginXml(
                     classNode,
                     '1.0',
                     ['Foo'] as Set,
@@ -98,15 +90,7 @@ class GlobalGrailsClassInjectorTransformationSpec extends 
Specification {
     void "a correct plugin xml file is updated when the plugin xml does 
exist"() {
         given: "a file that doesn't yet exist"
             def pluginXml = File.createTempFile('plugin-xml-gen-test', 
'.test.xml', tempDir)
-            def classNode = null
-            def cu = new CompilationUnit(new GroovyClassLoader())
-            cu.addSource('BarGrailsPlugin', 'class BarGrailsPlugin {}')
-            cu.addPhaseOperation({ SourceUnit source, GeneratorContext 
context, ClassNode cn ->
-                if (cn.name.endsWith('GrailsPlugin')) {
-                    classNode = cn
-                }
-            } as CompilationUnit.IPrimaryClassNodeOperation, Phases.CONVERSION)
-            cu.compile(Phases.CONVERSION)
+            def classNode = compilePlugin('class BarGrailsPlugin {}')
             pluginXml.text = '''
                 <plugin name="foo">
                     <type>FooGrailsPlugin</type>
@@ -122,7 +106,7 @@ class GlobalGrailsClassInjectorTransformationSpec extends 
Specification {
             pluginXml.exists()
 
         when: "the transformation generates the plugin.xml"
-            GlobalGrailsClassInjectorTransformation.generatePluginXml(
+            transformation.generatePluginXml(
                     classNode,
                     '1.0',
                     ['Foo', 'Bar'] as Set,
@@ -407,7 +391,7 @@ class GlobalGrailsClassInjectorTransformationSpec extends 
Specification {
             '''
 
         when: "the transformation updates the plugin.xml"
-            GlobalGrailsClassInjectorTransformation.generatePluginXml(
+            transformation.generatePluginXml(
                     classNode,
                     '2.0',
                     ['ExcludedThing', 'NewThing'] as Set,
@@ -429,23 +413,15 @@ class GlobalGrailsClassInjectorTransformationSpec extends 
Specification {
     void "plugin xml excludes are applied when writing a new descriptor"() {
         given:
             def pluginXml = new File(tempDir, 'plugin-xml-write-excludes.xml')
-            def classNode = null
-            def cu = new CompilationUnit(new GroovyClassLoader())
-            cu.addSource('WrittenExcludesGrailsPlugin', '''
+            def classNode = compilePlugin('''
                 class WrittenExcludesGrailsPlugin {
                     def pluginExcludes = ['Excluded*']
                     def grailsVersion = '4.0 > *'
                 }
             ''')
-            cu.addPhaseOperation({ SourceUnit source, GeneratorContext 
context, ClassNode cn ->
-                if (cn.name.endsWith('GrailsPlugin')) {
-                    classNode = cn
-                }
-            } as CompilationUnit.IPrimaryClassNodeOperation, Phases.CONVERSION)
-            cu.compile(Phases.CONVERSION)
 
         when:
-            GlobalGrailsClassInjectorTransformation.generatePluginXml(
+            transformation.generatePluginXml(
                     classNode,
                     '1.0',
                     ['ExcludedThing', 'KeptThing'] as Set,
@@ -468,7 +444,7 @@ class GlobalGrailsClassInjectorTransformationSpec extends 
Specification {
             '''
 
         when:
-            GlobalGrailsClassInjectorTransformation.generatePluginXml(
+            transformation.generatePluginXml(
                     null,
                     null,
                     ['NewThing'] as Set,
@@ -490,7 +466,7 @@ class GlobalGrailsClassInjectorTransformationSpec extends 
Specification {
             pluginXml.text = '<plugin><resources>'
 
         when: 'the transformation attempts to update the malformed plugin.xml'
-            GlobalGrailsClassInjectorTransformation.updatePluginXml(null, 
null, pluginXml, ['Foo'])
+            transformation.updatePluginXml(null, null, pluginXml, ['Foo'])
 
         then: 'no exception is thrown and a warning is logged'
             noExceptionThrown()
@@ -505,26 +481,6 @@ class GlobalGrailsClassInjectorTransformationSpec extends 
Specification {
             appender.stop()
     }
 
-    void "plugin xml exclusions remove matching resources from an existing 
descriptor"() {
-        given:
-            def pluginXml = new File(tempDir, 'existing-plugin-excludes.xml')
-            pluginXml.text = '''
-                <plugin>
-                    <resources>
-                        <resource>ExcludedThing</resource>
-                        <resource>KeptThing</resource>
-                    </resources>
-                </plugin>
-            '''
-            
GlobalGrailsClassInjectorTransformation.pluginExcludePatterns.add('Excluded*')
-
-        when:
-            GlobalGrailsClassInjectorTransformation.handleExcludes(new 
XmlSlurper().parse(pluginXml))
-
-        then:
-            noExceptionThrown()
-    }
-
     private SourceUnit sourceUnitWithTarget(File targetDirectory) {
         def cc = new CompilerConfiguration()
         cc.setTargetDirectory((File) targetDirectory)
@@ -534,6 +490,19 @@ class GlobalGrailsClassInjectorTransformationSpec extends 
Specification {
         }
     }
 
+    private static ClassNode compilePlugin(String pluginSource) {
+        def classNode = null
+        def cu = new CompilationUnit(new GroovyClassLoader())
+        cu.addSource('GrailsPlugin', pluginSource)
+        cu.addPhaseOperation({ SourceUnit source, GeneratorContext context, 
ClassNode cn ->
+            //if (cn.name.endsWith('GrailsPlugin')) {
+                classNode = cn
+            //}
+        } as CompilationUnit.IPrimaryClassNodeOperation, Phases.CONVERSION)
+        cu.compile(Phases.CONVERSION)
+        classNode
+    }
+
     /**
      * Compiles the given source to a real file on disk (required so {@code 
GrailsASTUtils.getSourceUrl}
      * resolves a URL). Because {@code 
GlobalGrailsClassInjectorTransformation} is itself registered as a

Reply via email to