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