You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2026/07/09 04:15:40 UTC

(groovy) branch master updated (07adcb35b9 -> aa30a69065)

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

paulk-asert pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git


    from 07adcb35b9 GROOVY-12134: @Delegate regression: fails to skip a final method inherited from a precompiled superclass
     new 49fb716307 Close GroovyClassLoader created for one-off compilation
     new aa30a69065 Close per-test GroovyClassLoader in contracts BaseTestClass

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../org/codehaus/groovy/ant/GenerateStubsTask.java | 58 ++++++++--------
 .../main/java/org/codehaus/groovy/ant/Groovy.java  |  4 ++
 .../java/org/codehaus/groovy/ant/GroovycTask.java  | 78 +++++++++++-----------
 .../console/ui/AstNodeToScriptAdapter.groovy       | 32 +++++----
 .../contracts/tests/basic/BaseTestClass.groovy     |  7 ++
 5 files changed, 100 insertions(+), 79 deletions(-)


(groovy) 01/02: Close GroovyClassLoader created for one-off compilation

Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

paulk-asert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 49fb716307b969179ac9946b69dd41fc2e2644c5
Author: Paul King <pa...@asert.com.au>
AuthorDate: Thu Jul 9 13:36:45 2026 +1000

    Close GroovyClassLoader created for one-off compilation
    
    The Groovyc and GenerateStubs Ant tasks and the console AstNodeToScriptAdapter
    each created a GroovyClassLoader for a single compilation and then discarded it
    without closing, leaking the loader's open file handles. Wrap each so the loader
    is closed once the compilation completes. The AST adapter only closes the loader
    it creates itself, leaving a caller-supplied loader untouched.
---
 .../org/codehaus/groovy/ant/GenerateStubsTask.java | 58 ++++++++--------
 .../main/java/org/codehaus/groovy/ant/Groovy.java  |  4 ++
 .../java/org/codehaus/groovy/ant/GroovycTask.java  | 78 +++++++++++-----------
 .../console/ui/AstNodeToScriptAdapter.groovy       | 32 +++++----
 4 files changed, 93 insertions(+), 79 deletions(-)

diff --git a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/GenerateStubsTask.java b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/GenerateStubsTask.java
index 87fc6c052c..25fa09ed06 100644
--- a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/GenerateStubsTask.java
+++ b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/GenerateStubsTask.java
@@ -25,6 +25,7 @@ import org.codehaus.groovy.control.Phases;
 import org.codehaus.groovy.tools.javac.JavaStubCompilationUnit;
 
 import java.io.File;
+import java.io.IOException;
 
 /**
  * Generates Java stubs from Groovy sources.
@@ -34,45 +35,46 @@ public class GenerateStubsTask extends CompileTaskSupport {
      * Generates Java stubs for the configured source roots.
      */
     @Override
-    protected void compile() {
-        GroovyClassLoader gcl = createClassLoader();
-        JavaStubCompilationUnit cu = new JavaStubCompilationUnit(config, gcl, destdir);
+    protected void compile() throws IOException {
+        try (GroovyClassLoader gcl = createClassLoader()) {
+            JavaStubCompilationUnit cu = new JavaStubCompilationUnit(config, gcl, destdir);
 
-        int count = 0;
+            int count = 0;
 
-        for (String srcPath : src.list()) {
-            File srcDir = getProject().resolveFile(srcPath);
-            if (!srcDir.exists()) {
-                throw new BuildException("Source directory does not exist: " + srcDir, getLocation());
-            }
+            for (String srcPath : src.list()) {
+                File srcDir = getProject().resolveFile(srcPath);
+                if (!srcDir.exists()) {
+                    throw new BuildException("Source directory does not exist: " + srcDir, getLocation());
+                }
 
-            DirectoryScanner scanner = getDirectoryScanner(srcDir);
+                DirectoryScanner scanner = getDirectoryScanner(srcDir);
 
-            log.debug("Including files from: " + srcDir);
+                log.debug("Including files from: " + srcDir);
 
-            for (String includeName : scanner.getIncludedFiles()) {
-                log.debug("    " + includeName);
+                for (String includeName : scanner.getIncludedFiles()) {
+                    log.debug("    " + includeName);
 
-                File file = new File(srcDir, includeName);
+                    File file = new File(srcDir, includeName);
 
-                if (isSource(includeName)) {
-                    cu.addSource(file);
-                }
+                    if (isSource(includeName)) {
+                        cu.addSource(file);
+                    }
 
-                // Increment the count for each groovy src we found
-                // TODO support config.getScriptExtensions()?
-                if (includeName.endsWith(config.getDefaultScriptExtension())) {
-                    count++;
+                    // Increment the count for each groovy src we found
+                    // TODO support config.getScriptExtensions()?
+                    if (includeName.endsWith(config.getDefaultScriptExtension())) {
+                        count++;
+                    }
                 }
             }
-        }
 
-        if (count > 0) {
-            log.info("Generating " + count + " Java stub" + (count > 1 ? "s" : "") + " to " + destdir);
-            cu.compile(Phases.CONVERSION); // Generate the stubs
-            log.info("Generated " + cu.getStubCount() + " Java stub(s)");
-        } else {
-            log.info("No sources found for stub generation");
+            if (count > 0) {
+                log.info("Generating " + count + " Java stub" + (count > 1 ? "s" : "") + " to " + destdir);
+                cu.compile(Phases.CONVERSION); // Generate the stubs
+                log.info("Generated " + cu.getStubCount() + " Java stub(s)");
+            } else {
+                log.info("No sources found for stub generation");
+            }
         }
     }
 
diff --git a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovy.java b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovy.java
index c62eb29ca7..7d23896e5b 100644
--- a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovy.java
+++ b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovy.java
@@ -599,6 +599,10 @@ public class Groovy extends Java {
             groovy.resetLoadedClasses();
             groovy.getClassLoader().clearCache();
             if (contextClassLoader || maven) thread.setContextClassLoader(savedLoader);
+            try {
+                classLoader.close();
+            } catch (IOException ignore) {
+            }
         }
     }
 
diff --git a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/GroovycTask.java b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/GroovycTask.java
index 648246efbb..b6d6d78336 100644
--- a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/GroovycTask.java
+++ b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/GroovycTask.java
@@ -27,6 +27,7 @@ import org.apache.tools.ant.util.SourceFileScanner;
 import org.codehaus.groovy.control.CompilationUnit;
 
 import java.io.File;
+import java.io.IOException;
 
 /**
  * Compiles Groovy source files.
@@ -52,7 +53,7 @@ public class GroovycTask
      * Compiles the configured Groovy sources.
      */
     @Override
-    protected void compile() {
+    protected void compile() throws IOException {
         Path path = getClasspath();
         if (path != null) {
             config.setClasspath(path.toString());
@@ -60,58 +61,59 @@ public class GroovycTask
 
         config.setTargetDirectory(destdir);
 
-        GroovyClassLoader gcl = createClassLoader();
-        CompilationUnit compilation = new CompilationUnit(config, null, gcl);
+        try (GroovyClassLoader gcl = createClassLoader()) {
+            CompilationUnit compilation = new CompilationUnit(config, null, gcl);
 
-        GlobPatternMapper mapper = new GlobPatternMapper();
-        mapper.setFrom("*.groovy");
-        mapper.setTo("*.class");
+            GlobPatternMapper mapper = new GlobPatternMapper();
+            mapper.setFrom("*.groovy");
+            mapper.setTo("*.class");
 
-        int count = 0;
-        String[] list = src.list();
+            int count = 0;
+            String[] list = src.list();
 
-        for (String s : list) {
-            File basedir = getProject().resolveFile(s);
+            for (String s : list) {
+                File basedir = getProject().resolveFile(s);
 
-            if (!basedir.exists()) {
-                throw new BuildException("Source directory does not exist: " + basedir, getLocation());
-            }
+                if (!basedir.exists()) {
+                    throw new BuildException("Source directory does not exist: " + basedir, getLocation());
+                }
 
-            DirectoryScanner scanner = getDirectoryScanner(basedir);
-            String[] includes = scanner.getIncludedFiles();
+                DirectoryScanner scanner = getDirectoryScanner(basedir);
+                String[] includes = scanner.getIncludedFiles();
 
-            if (force) {
-                log.debug("Forcefully including all files from: " + basedir);
+                if (force) {
+                    log.debug("Forcefully including all files from: " + basedir);
 
-                for (String include : includes) {
-                    File file = new File(basedir, include);
-                    log.debug("    " + file);
+                    for (String include : includes) {
+                        File file = new File(basedir, include);
+                        log.debug("    " + file);
 
-                    compilation.addSource(file);
-                    count++;
-                }
-            } else {
-                log.debug("Including changed files from: " + basedir);
+                        compilation.addSource(file);
+                        count++;
+                    }
+                } else {
+                    log.debug("Including changed files from: " + basedir);
 
-                SourceFileScanner sourceScanner = new SourceFileScanner(this);
-                File[] files = sourceScanner.restrictAsFiles(includes, basedir, destdir, mapper);
+                    SourceFileScanner sourceScanner = new SourceFileScanner(this);
+                    File[] files = sourceScanner.restrictAsFiles(includes, basedir, destdir, mapper);
 
-                for (File file : files) {
-                    log.debug("    " + file);
+                    for (File file : files) {
+                        log.debug("    " + file);
 
-                    compilation.addSource(file);
-                    count++;
+                        compilation.addSource(file);
+                        count++;
+                    }
                 }
             }
-        }
 
-        if (count > 0) {
-            log.info("Compiling " + count + " source file" + (count > 1 ? "s" : "") + " to " + destdir);
+            if (count > 0) {
+                log.info("Compiling " + count + " source file" + (count > 1 ? "s" : "") + " to " + destdir);
 
-            compilation.compile();
-        }
-        else {
-            log.info("No sources found to compile");
+                compilation.compile();
+            }
+            else {
+                log.info("No sources found to compile");
+            }
         }
     }
 }
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy
index 94752b740b..9f13c48a29 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/AstNodeToScriptAdapter.groovy
@@ -159,21 +159,27 @@ and [compilephase] is a valid Integer based org.codehaus.groovy.control.CompileP
         def writer = new StringBuilderWriter()
         def scriptName = 'script' + System.currentTimeMillis() + '.groovy'
         GroovyCodeSource codeSource = new GroovyCodeSource(script, scriptName, '/groovy/script')
-        CompilationUnit cu = new CompilationUnit((CompilerConfiguration) (config ?: CompilerConfiguration.DEFAULT), (CodeSource) codeSource.codeSource, (GroovyClassLoader) classLoader ?: new GroovyClassLoader(this.class.classLoader))
-        cu.addPhaseOperation(new AstNodeToScriptVisitor(writer, showScriptFreeForm, showScriptClass), compilePhase)
-        cu.addSource(codeSource.getName(), script)
+        boolean ownLoader = classLoader == null
+        GroovyClassLoader loader = (GroovyClassLoader) classLoader ?: new GroovyClassLoader(this.class.classLoader)
         try {
-            cu.compile(compilePhase)
-        } catch (CompilationFailedException cfe) {
-            writer.println 'Unable to produce AST for this phase due to earlier compilation error:'
-            cfe.message.eachLine {
-                writer.println it
+            CompilationUnit cu = new CompilationUnit((CompilerConfiguration) (config ?: CompilerConfiguration.DEFAULT), (CodeSource) codeSource.codeSource, loader)
+            cu.addPhaseOperation(new AstNodeToScriptVisitor(writer, showScriptFreeForm, showScriptClass), compilePhase)
+            cu.addSource(codeSource.getName(), script)
+            try {
+                cu.compile(compilePhase)
+            } catch (CompilationFailedException cfe) {
+                writer.println 'Unable to produce AST for this phase due to earlier compilation error:'
+                cfe.message.eachLine {
+                    writer.println it
+                }
+                writer.println 'Fix the above error(s) and then press Refresh'
+            } catch (Throwable t) {
+                writer.println 'Unable to produce AST for this phase due to an error:'
+                writer.println t.getMessage()
+                writer.println 'Fix the above error(s) and then press Refresh'
             }
-            writer.println 'Fix the above error(s) and then press Refresh'
-        } catch (Throwable t) {
-            writer.println 'Unable to produce AST for this phase due to an error:'
-            writer.println t.getMessage()
-            writer.println 'Fix the above error(s) and then press Refresh'
+        } finally {
+            if (ownLoader) loader.close()
         }
         return writer.toString()
     }


(groovy) 02/02: Close per-test GroovyClassLoader in contracts BaseTestClass

Posted by pa...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

paulk-asert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit aa30a6906577f66a707a6522ca67d7a233117b80
Author: Paul King <pa...@asert.com.au>
AuthorDate: Thu Jul 9 13:36:46 2026 +1000

    Close per-test GroovyClassLoader in contracts BaseTestClass
    
    BaseTestClass created a GroovyClassLoader in @BeforeEach but never closed it,
    so every contracts test that extended it leaked a loader. Add an @AfterEach
    that closes the loader, mirroring StubTestCase.
---
 .../org/apache/groovy/contracts/tests/basic/BaseTestClass.groovy   | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/subprojects/groovy-contracts/src/test/groovy/org/apache/groovy/contracts/tests/basic/BaseTestClass.groovy b/subprojects/groovy-contracts/src/test/groovy/org/apache/groovy/contracts/tests/basic/BaseTestClass.groovy
index 95a7c251b6..e1ceccafd6 100644
--- a/subprojects/groovy-contracts/src/test/groovy/org/apache/groovy/contracts/tests/basic/BaseTestClass.groovy
+++ b/subprojects/groovy-contracts/src/test/groovy/org/apache/groovy/contracts/tests/basic/BaseTestClass.groovy
@@ -21,6 +21,7 @@ package org.apache.groovy.contracts.tests.basic
 import groovy.text.GStringTemplateEngine
 import groovy.text.TemplateEngine
 import org.codehaus.groovy.runtime.ScriptBytecodeAdapter
+import org.junit.jupiter.api.AfterEach
 import org.junit.jupiter.api.BeforeEach
 
 import static org.junit.jupiter.api.Assertions.assertTrue
@@ -39,6 +40,12 @@ class BaseTestClass {
         loader = new GroovyClassLoader(getClass().getClassLoader())
     }
 
+    @AfterEach
+    void tearDown() {
+        loader?.close()
+        loader = null
+    }
+
     String createSourceCodeForTemplate(final String template, final Map binding) {
         templateEngine.createTemplate(template).make(binding).toString()
     }