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

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


The following commit(s) were added to refs/heads/master by this push:
     new 3ae57630c5 GROOVY-11886: support JDK platform logging instead of 
System.err for errors and warnings (#2409)
3ae57630c5 is described below

commit 3ae57630c5c8ebb6d7a0b73193f757147b54944b
Author: Paul King <[email protected]>
AuthorDate: Sun Mar 29 13:45:25 2026 +1100

    GROOVY-11886: support JDK platform logging instead of System.err for errors 
and warnings (#2409)
---
 src/main/java/groovy/grape/Grape.java              | 29 +++++++++--------
 src/main/java/groovy/ui/GroovyMain.java            |  8 +++--
 .../java/org/apache/groovy/antlr/LexerFrame.java   |  4 ++-
 .../codehaus/groovy/classgen/asm/OperandStack.java |  6 +++-
 .../classgen/asm/util/LoggableTextifier.java       | 14 ++++----
 .../org/codehaus/groovy/control/XStreamUtils.java  | 12 ++++---
 .../org/codehaus/groovy/tools/DgmConverter.java    |  6 +++-
 .../codehaus/groovy/tools/FileSystemCompiler.java  | 16 ++++++----
 .../org/codehaus/groovy/tools/GroovyStarter.java   |  8 +++--
 .../groovy/tools/javac/JavacJavaCompiler.java      |  6 +++-
 src/test/groovy/bugs/Groovy10281.groovy            | 37 +++++++++++++++++-----
 .../main/java/org/codehaus/groovy/ant/Groovyc.java |  6 +++-
 .../java/org/codehaus/groovy/ant/Groovydoc.java    |  7 ++--
 .../org/codehaus/groovy/ant/GroovycTest.java       | 28 ++++++++++++----
 .../groovy/console/ui/ConsoleTextEditor.java       |  5 ++-
 .../groovy/tools/groovydoc/FileOutputTool.java     |  8 +++--
 .../tools/groovydoc/GroovyDocTemplateEngine.java   | 21 +++++++-----
 .../tools/groovydoc/GroovyRootDocBuilder.java      |  4 ++-
 .../tools/groovydoc/antlr4/GroovyDocParser.java    | 17 ++++++----
 .../groovy/tools/groovydoc/GroovyDocToolTest.java  | 35 ++------------------
 .../apache/groovy/json/internal/Exceptions.java    | 10 +++---
 .../java/org/apache/groovy/json/internal/Sys.java  |  7 ++--
 .../main/java/groovy/servlet/GroovyServlet.java    | 14 +++++---
 .../main/java/groovy/swing/table/TableSorter.java  |  5 ++-
 .../java/groovy/junit5/plugin/JUnit5Runner.java    |  6 +++-
 .../src/main/java/groovy/test/GroovyTestSuite.java |  6 +++-
 26 files changed, 205 insertions(+), 120 deletions(-)

diff --git a/src/main/java/groovy/grape/Grape.java 
b/src/main/java/groovy/grape/Grape.java
index 650762e0ef..3ed8cb49c4 100644
--- a/src/main/java/groovy/grape/Grape.java
+++ b/src/main/java/groovy/grape/Grape.java
@@ -26,11 +26,17 @@ import java.util.Map;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
 
+import static java.lang.System.Logger.Level.DEBUG;
+import static java.lang.System.Logger.Level.ERROR;
+import static java.lang.System.Logger.Level.WARNING;
+
 /**
  * Facade to GrapeEngine.
  */
 public class Grape {
 
+    private static final System.Logger LOGGER = 
System.getLogger(Grape.class.getName());
+
     public static final String AUTO_DOWNLOAD_SETTING = "autoDownload";
     public static final String DISABLE_CHECKSUMS_SETTING = "disableChecksums";
     public static final String SYSTEM_PROPERTIES_SETTING = "systemProperties";
@@ -128,7 +134,7 @@ public class Grape {
                 instance = createEngineFromProvider(provider);
             }
             if (instance == null) {
-                System.err.println("Grape: Grapes disabled.");
+                LOGGER.log(WARNING, "Grapes disabled");
             }
         }
         return instance;
@@ -151,7 +157,7 @@ public class Grape {
             }
             providers = discovered.values().stream().toList();
         } catch (ServiceConfigurationError sce) {
-            System.err.println("Grape: failed to discover service providers 
for " + GrapeEngine.class.getName() + ": " + sce.getMessage());
+            LOGGER.log(ERROR, "Failed to discover service providers for {0}: 
{1}", GrapeEngine.class.getName(), sce.getMessage());
             return null;
         }
 
@@ -160,13 +166,12 @@ public class Grape {
                 if (provider.type().getName().equals(configuredImpl)) {
                     providers.stream()
                             .filter(p -> 
!p.type().getName().equals(configuredImpl))
-                            .forEach(p -> System.err.println("Grape: ignoring 
provider '" + p.type().getName()
-                                    + "' ('" + configuredImpl + "' configured 
via -D" + GRAPE_IMPL_SYSTEM_PROPERTY + ")."));
+                            .forEach(p -> LOGGER.log(DEBUG, "Ignoring provider 
''{0}'' (''{1}'' configured via -D{2})",
+                                    p.type().getName(), configuredImpl, 
GRAPE_IMPL_SYSTEM_PROPERTY));
                     return provider;
                 }
             }
-            System.err.println("Grape: configured implementation '" + 
configuredImpl
-                    + "' not found via service loader.");
+            LOGGER.log(WARNING, "Configured implementation ''{0}'' not found 
via service loader", configuredImpl);
             return null;
         }
 
@@ -179,17 +184,15 @@ public class Grape {
                 if (provider.type().getName().equals(DEFAULT_GRAPE_ENGINE)) {
                     providers.stream()
                             .filter(p -> 
!p.type().getName().equals(DEFAULT_GRAPE_ENGINE))
-                            .forEach(p -> System.err.println("Grape: ignoring 
provider '" + p.type().getName()
-                                    + "' in favour of default '" + 
DEFAULT_GRAPE_ENGINE
-                                    + "' (set -D" + GRAPE_IMPL_SYSTEM_PROPERTY 
+ " to override)."));
+                            .forEach(p -> LOGGER.log(DEBUG, "Ignoring provider 
''{0}'' in favour of default ''{1}'' (set -D{2} to override)",
+                                    p.type().getName(), DEFAULT_GRAPE_ENGINE, 
GRAPE_IMPL_SYSTEM_PROPERTY));
                     return provider;
                 }
             }
             // Multiple providers discovered but the default is not among them.
             List<String> names = providers.stream().map(p -> 
p.type().getName()).toList();
-            System.err.println("Grape: " + providers.size() + " providers 
discovered " + names
-                    + " but default '" + DEFAULT_GRAPE_ENGINE + "' is not 
among them;"
-                    + " set -D" + GRAPE_IMPL_SYSTEM_PROPERTY + " to select 
one.");
+            LOGGER.log(WARNING, "{0} providers discovered {1} but default 
''{2}'' is not among them; set -D{3} to select one",
+                    providers.size(), names, DEFAULT_GRAPE_ENGINE, 
GRAPE_IMPL_SYSTEM_PROPERTY);
         }
 
         // No system property set: empty list means security lockdown — return 
null silently.
@@ -200,7 +203,7 @@ public class Grape {
         try {
             return provider.get();
         } catch (ServiceConfigurationError sce) {
-            System.err.println("Grape: failed to instantiate service provider 
'" + provider.type().getName() + "': " + sce.getMessage());
+            LOGGER.log(ERROR, "Failed to instantiate service provider ''{0}'': 
{1}", provider.type().getName(), sce.getMessage());
             return null;
         }
     }
diff --git a/src/main/java/groovy/ui/GroovyMain.java 
b/src/main/java/groovy/ui/GroovyMain.java
index 66b2d9c539..dc22909d61 100644
--- a/src/main/java/groovy/ui/GroovyMain.java
+++ b/src/main/java/groovy/ui/GroovyMain.java
@@ -61,11 +61,15 @@ import java.util.List;
 import java.util.Map;
 import java.util.regex.Pattern;
 
+import static java.lang.System.Logger.Level.ERROR;
+
 /**
  * A Command line to execute groovy.
  */
 public class GroovyMain {
 
+    private static final System.Logger LOGGER = 
System.getLogger(GroovyMain.class.getName());
+
     // arguments to the script
     private List<String> args;
 
@@ -390,13 +394,13 @@ public class GroovyMain {
             }
             return true;
         } catch (CompilationFailedException e) {
-            System.err.println(e);
+            LOGGER.log(ERROR, e.toString());
             return false;
         } catch (Throwable e) {
             if (e instanceof InvokerInvocationException iie) {
                 e = iie.getCause();
             }
-            System.err.println("Caught: " + e);
+            LOGGER.log(ERROR, "Caught: {0}", e);
             if (!debug) {
                 StackTraceUtils.deepSanitize(e);
             }
diff --git a/src/main/java/org/apache/groovy/antlr/LexerFrame.java 
b/src/main/java/org/apache/groovy/antlr/LexerFrame.java
index dac1ee40ee..8259297b3d 100644
--- a/src/main/java/org/apache/groovy/antlr/LexerFrame.java
+++ b/src/main/java/org/apache/groovy/antlr/LexerFrame.java
@@ -61,10 +61,12 @@ import java.lang.reflect.Modifier;
 import java.util.HashMap;
 import java.util.Map;
 
+
 /**
  * Swing application to graphically display the tokens produced by the lexer.
  */
 public class LexerFrame extends JFrame implements ActionListener {
+    private static final System.Logger LOGGER = 
System.getLogger(LexerFrame.class.getName());
     private static final long serialVersionUID = 2715693043143492893L;
     private static final Class<GroovyLexer> TOKEN_TYPES_CLASS = 
GroovyLexer.class;
     private static final Font MONOSPACED_FONT = new Font("Monospaced", 
Font.PLAIN, 12);
@@ -292,7 +294,7 @@ public class LexerFrame extends JFrame implements 
ActionListener {
         if (args.length == 0) {
             lexerFrame = new LexerFrame();
         } else if (args.length > 1) {
-            System.err.println("usage: java LexerFrame [filename.ext]");
+            LOGGER.log(System.Logger.Level.ERROR, "usage: java LexerFrame 
[filename.ext]");
             System.exit(1);
         } else {
             String filename = args[0];
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/OperandStack.java 
b/src/main/java/org/codehaus/groovy/classgen/asm/OperandStack.java
index 734d3afe97..0c74b8abac 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/OperandStack.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/OperandStack.java
@@ -36,6 +36,8 @@ import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.List;
 
+import static java.lang.System.Logger.Level.ERROR;
+
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveBoolean;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveByte;
 import static org.codehaus.groovy.ast.ClassHelper.isPrimitiveChar;
@@ -88,6 +90,8 @@ import static org.objectweb.asm.Opcodes.SWAP;
 
 public class OperandStack {
 
+    private static final System.Logger LOGGER = 
System.getLogger(OperandStack.class.getName());
+
     private final List<ClassNode> stack = new ArrayList<>();
     private final WriterController controller;
 
@@ -281,7 +285,7 @@ public class OperandStack {
         try {
             if (size == 0) throw new ArrayIndexOutOfBoundsException("size==0");
         } catch (ArrayIndexOutOfBoundsException ai) {
-            System.err.println("index problem in " + 
controller.getSourceUnit().getName());
+            LOGGER.log(ERROR, "Index problem in {0}", 
controller.getSourceUnit().getName());
             throw ai;
         }
 
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableTextifier.java 
b/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableTextifier.java
index 0da008d90b..069491a6ab 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableTextifier.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/util/LoggableTextifier.java
@@ -26,13 +26,13 @@ import org.objectweb.asm.TypePath;
 import org.objectweb.asm.util.Printer;
 import org.objectweb.asm.util.Textifier;
 
-import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import java.util.Optional;
 import java.util.stream.Collectors;
 
+import static java.lang.System.Logger.Level.DEBUG;
+
 /**
  * Logging bytecode generation, which can make debugging easy
  *
@@ -40,8 +40,9 @@ import java.util.stream.Collectors;
  */
 public class LoggableTextifier extends Textifier {
 
+    private static final System.Logger LOGGER = 
System.getLogger(LoggableTextifier.class.getName());
+
     private final CompilerConfiguration compilerConfiguration;
-    private final PrintWriter out;
     private int lineCount;
 
     public LoggableTextifier() {
@@ -51,7 +52,6 @@ public class LoggableTextifier extends Textifier {
     public LoggableTextifier(final CompilerConfiguration 
compilerConfiguration) {
         super(CompilerConfiguration.ASM_API_VERSION);
         this.compilerConfiguration = compilerConfiguration;
-        this.out = 
Optional.ofNullable(compilerConfiguration.getOutput()).orElseGet(() -> new 
PrintWriter(System.out, true));
     }
 
     @Override
@@ -69,10 +69,12 @@ public class LoggableTextifier extends Textifier {
             }
         }
         if (!bcList.isEmpty()) {
-            out.print(getInvocationPositionInfo());
+            StringBuilder sb = new StringBuilder();
+            sb.append(getInvocationPositionInfo());
             for (Object bc : bcList) {
-                out.print(bc);
+                sb.append(bc);
             }
+            LOGGER.log(DEBUG, sb.toString());
         }
         lineCount = textSize;
     }
diff --git a/src/main/java/org/codehaus/groovy/control/XStreamUtils.java 
b/src/main/java/org/codehaus/groovy/control/XStreamUtils.java
index 1369e414fa..8fbb758245 100644
--- a/src/main/java/org/codehaus/groovy/control/XStreamUtils.java
+++ b/src/main/java/org/codehaus/groovy/control/XStreamUtils.java
@@ -26,8 +26,13 @@ import java.io.File;
 import java.io.FileWriter;
 import java.net.URI;
 
+import static java.lang.System.Logger.Level.DEBUG;
+import static java.lang.System.Logger.Level.WARNING;
+
 public abstract class XStreamUtils {
 
+    private static final System.Logger LOGGER = 
System.getLogger(XStreamUtils.class.getName());
+
     public static void serialize(final String name, final Object ast) {
         if (name == null || name.isEmpty()) return;
 
@@ -36,16 +41,15 @@ public abstract class XStreamUtils {
         try {
             File astFile = astFile(name);
             if (astFile == null) {
-                System.out.println("File-name for writing " + name + " AST 
could not be determined!");
+                LOGGER.log(WARNING, "File-name for writing {0} AST could not 
be determined!", name);
                 return;
             }
             astFileWriter = new FileWriter(astFile, false);
             xstream.toXML(ast, astFileWriter);
-            System.out.println("Written AST to " + name + ".xml");
+            LOGGER.log(DEBUG, "Written AST to {0}.xml", name);
 
         } catch (Exception e) {
-            System.out.println("Couldn't write to " + name + ".xml");
-            e.printStackTrace();
+            LOGGER.log(WARNING, "Couldn''t write to " + name + ".xml", e);
         } finally {
             DefaultGroovyMethods.closeQuietly(astFileWriter);
         }
diff --git a/src/main/java/org/codehaus/groovy/tools/DgmConverter.java 
b/src/main/java/org/codehaus/groovy/tools/DgmConverter.java
index 57677874b3..04e74e7c39 100644
--- a/src/main/java/org/codehaus/groovy/tools/DgmConverter.java
+++ b/src/main/java/org/codehaus/groovy/tools/DgmConverter.java
@@ -37,6 +37,8 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
+import static java.lang.System.Logger.Level.INFO;
+
 import static org.objectweb.asm.Opcodes.AALOAD;
 import static org.objectweb.asm.Opcodes.ACC_FINAL;
 import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
@@ -57,6 +59,8 @@ import static org.objectweb.asm.Opcodes.RETURN;
 
 public class DgmConverter {
 
+    private static final System.Logger LOGGER = 
System.getLogger(DgmConverter.class.getName());
+
     public static void main(String[] args) throws IOException {
         String targetDirectory = "build/classes/";
         boolean info = (args.length == 1 && "--info".equals(args[0]))
@@ -124,7 +128,7 @@ public class DgmConverter {
 
         GeneratedMetaMethod.DgmMethodRecord.saveDgmInfo(records, 
targetDirectory+"/META-INF/dgminfo");
         if (info)
-            System.out.println("Saved " + cur + " dgm records to: 
"+targetDirectory+"/META-INF/dgminfo");
+            LOGGER.log(INFO, "Saved {0} dgm records to: {1}/META-INF/dgminfo", 
cur, targetDirectory);
     }
 
     private static void createConstructor(ClassWriter cw) {
diff --git a/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java 
b/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java
index 02e0e49234..f8fc8e13e4 100644
--- a/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java
+++ b/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java
@@ -48,12 +48,16 @@ import java.util.Map;
 import static groovy.ui.GroovyMain.buildConfigScriptText;
 import static groovy.ui.GroovyMain.processConfigScriptText;
 import static groovy.ui.GroovyMain.processConfigScripts;
+import static java.lang.System.Logger.Level.ERROR;
+import static java.lang.System.Logger.Level.WARNING;
 
 /**
  * Command-line compiler (aka. <tt>groovyc</tt>).
  */
 public class FileSystemCompiler {
 
+    private static final System.Logger LOGGER = 
System.getLogger(FileSystemCompiler.class.getName());
+
     private static boolean displayStackTraceOnError = false;
     private final CompilationUnit unit;
 
@@ -116,10 +120,10 @@ public class FileSystemCompiler {
         for (String filename : filenames) {
             File file = new File(filename);
             if (!file.exists()) {
-                System.err.println("error: file not found: " + file);
+                LOGGER.log(ERROR, "File not found: {0}", file);
                 errors += 1;
             } else if (!file.canRead()) {
-                System.err.println("error: file not readable: " + file);
+                LOGGER.log(ERROR, "File not readable: {0}", file);
                 errors += 1;
             }
         }
@@ -244,7 +248,7 @@ public class FileSystemCompiler {
             try {
                 if (tmpDir != null) deleteRecursive(tmpDir);
             } catch (Throwable t) {
-                System.err.println("error: could not delete temp files - " + 
tmpDir.getPath());
+                LOGGER.log(WARNING, "Could not delete temp files - {0}", 
tmpDir.getPath());
             }
         }
     }
@@ -269,14 +273,14 @@ public class FileSystemCompiler {
                         fileList.add(file);
                     }
                 } catch (IOException ioe) {
-                    System.err.println("error: file not readable: " + fn);
+                    LOGGER.log(ERROR, "File not readable: {0}", fn);
                     errors = true;
                 } finally {
                     if (null != br) {
                         try {
                             br.close();
                         } catch (IOException e) {
-                            System.err.println("error: failed to close 
buffered reader: " + fn);
+                            LOGGER.log(WARNING, "Failed to close buffered 
reader: {0}", fn);
                             errors = true;
                         }
                     }
@@ -440,7 +444,7 @@ public class FileSystemCompiler {
                     || Integer.parseInt(warningLevel) == 
WarningMessage.PARANOIA) {
                 configuration.setWarningLevel(Integer.parseInt(warningLevel));
             } else {
-                System.err.println("error: warning level not recognized: " + 
warningLevel);
+                LOGGER.log(ERROR, "Warning level not recognized: {0}", 
warningLevel);
             }
 
             // joint compilation parameters
diff --git a/src/main/java/org/codehaus/groovy/tools/GroovyStarter.java 
b/src/main/java/org/codehaus/groovy/tools/GroovyStarter.java
index 0e1130ab89..41063810f0 100644
--- a/src/main/java/org/codehaus/groovy/tools/GroovyStarter.java
+++ b/src/main/java/org/codehaus/groovy/tools/GroovyStarter.java
@@ -22,11 +22,15 @@ import java.io.FileInputStream;
 import java.lang.reflect.Method;
 import java.util.Arrays;
 
+import static java.lang.System.Logger.Level.ERROR;
+
 /**
  * Helper class to initialize the Groovy runtime.
  */
 public class GroovyStarter {
 
+    private static final System.Logger LOGGER = 
System.getLogger(GroovyStarter.class.getName());
+
     static void printUsage() {
         System.out.println("possible programs are 
'groovyc','groovy','console', and 'groovysh'");
         System.exit(1);
@@ -98,7 +102,7 @@ public class GroovyStarter {
             try {
                 lc.configure(new FileInputStream(conf));
             } catch (Exception e) {
-                System.err.println("exception while configuring main class 
loader:");
+                LOGGER.log(ERROR, "Exception while configuring main class 
loader");
                 exit(e);
             }
         }
@@ -128,7 +132,7 @@ public class GroovyStarter {
     }
 
     private static void exit(String text) {
-        System.err.println(text);
+        LOGGER.log(ERROR, text);
         System.exit(1);
     }
 }
diff --git 
a/src/main/java/org/codehaus/groovy/tools/javac/JavacJavaCompiler.java 
b/src/main/java/org/codehaus/groovy/tools/javac/JavacJavaCompiler.java
index 86d49ef8ba..a104800d19 100644
--- a/src/main/java/org/codehaus/groovy/tools/javac/JavacJavaCompiler.java
+++ b/src/main/java/org/codehaus/groovy/tools/javac/JavacJavaCompiler.java
@@ -41,8 +41,12 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 
+import static java.lang.System.Logger.Level.INFO;
+
 public class JavacJavaCompiler implements JavaCompiler {
 
+    private static final System.Logger LOGGER = 
System.getLogger(JavacJavaCompiler.class.getName());
+
     private final CompilerConfiguration config;
 
     public JavacJavaCompiler(final CompilerConfiguration config) {
@@ -76,7 +80,7 @@ public class JavacJavaCompiler implements JavaCompiler {
                 default -> "unexpected return value by javac.";
             }, javacOutput.toString(), cu);
         } else {
-            System.out.print(javacOutput); // print errors/warnings
+            LOGGER.log(INFO, javacOutput.toString()); // javac errors/warnings
         }
     }
 
diff --git a/src/test/groovy/bugs/Groovy10281.groovy 
b/src/test/groovy/bugs/Groovy10281.groovy
index 8b0c17bfff..22eadf88fa 100644
--- a/src/test/groovy/bugs/Groovy10281.groovy
+++ b/src/test/groovy/bugs/Groovy10281.groovy
@@ -23,6 +23,10 @@ import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.Phases
 import org.junit.jupiter.api.Test
 
+import java.util.logging.Handler
+import java.util.logging.LogRecord
+import java.util.logging.Logger
+
 final class Groovy10281 {
 
     @Test
@@ -53,17 +57,34 @@ final class Groovy10281 {
         def code = """
                 println 'Hello, world!'
             """
-        def result = new StringWriter()
-        PrintWriter pw = new PrintWriter(result)
-        def config = stacktrace ? new CompilerConfiguration(logClassgen: true, 
logClassgenStackTraceMaxDepth: maxDepth, output: pw)
-                                                    : new 
CompilerConfiguration(logClassgen: true, output: pw)
+        def result = new StringBuilder()
+
+        // Capture System.Logger output via JUL handler
+        def loggerName = 
'org.codehaus.groovy.classgen.asm.util.LoggableTextifier'
+        def julLogger = Logger.getLogger(loggerName)
+        def originalLevel = julLogger.level
+        julLogger.level = java.util.logging.Level.ALL
+        def handler = new Handler() {
+            void publish(LogRecord record) { result.append(record.message) }
+            void flush() {}
+            void close() {}
+        }
+        handler.level = java.util.logging.Level.ALL
+        julLogger.addHandler(handler)
+
+        try {
+            def config = stacktrace ? new CompilerConfiguration(logClassgen: 
true, logClassgenStackTraceMaxDepth: maxDepth)
+                                    : new CompilerConfiguration(logClassgen: 
true)
 
-        new CompilationUnit(config).with {
-            addSource 'helloWorld.groovy', code
-            compile Phases.CLASS_GENERATION
+            new CompilationUnit(config).with {
+                addSource 'helloWorld.groovy', code
+                compile Phases.CLASS_GENERATION
+            }
+        } finally {
+            julLogger.removeHandler(handler)
+            julLogger.level = originalLevel
         }
 
-        pw.close()
         return result.toString()
     }
 }
diff --git 
a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java 
b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
index 7c04b4c335..9f4821270f 100644
--- a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
+++ b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
@@ -61,6 +61,8 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.StringTokenizer;
 
+import static java.lang.System.Logger.Level.WARNING;
+
 /**
  * Compiles Groovy source files using Ant.
  * <p>
@@ -174,6 +176,8 @@ import java.util.StringTokenizer;
  */
 public class Groovyc extends MatchingTask {
 
+    private static final System.Logger LOGGER = 
System.getLogger(Groovyc.class.getName());
+
     private static final File[] EMPTY_FILE_ARRAY = {};
 
     private final LoggingHelper log = new LoggingHelper(this);
@@ -1343,7 +1347,7 @@ public class Groovyc extends MatchingTask {
                 try {
                     FileSystemCompiler.deleteRecursive(temporaryFile);
                 } catch (Throwable t) {
-                    System.err.println("error: could not delete temp files - " 
+ temporaryFile.getPath());
+                    LOGGER.log(WARNING, "Could not delete temp files - {0}", 
temporaryFile.getPath());
                 }
             }
         }
diff --git 
a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovydoc.java 
b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovydoc.java
index 5e21730a37..b23f4b0c95 100644
--- 
a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovydoc.java
+++ 
b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovydoc.java
@@ -39,10 +39,13 @@ import java.util.List;
 import java.util.Properties;
 import java.util.StringTokenizer;
 
+import static java.lang.System.Logger.Level.WARNING;
+
 /**
  * Access to the GroovyDoc tool from Ant.
  */
 public class Groovydoc extends Task {
+    private static final System.Logger LOGGER = 
System.getLogger(Groovydoc.class.getName());
     private final LoggingHelper log = new LoggingHelper(this);
 
     private Path sourcePath;
@@ -494,8 +497,8 @@ public class Groovydoc extends Task {
                 File outfile = new File(destDir, "stylesheet.css");
                 ResourceGroovyMethods.setText(outfile, css);
             } catch (IOException e) {
-                System.out.println("Warning: Unable to copy specified 
stylesheet '" + styleSheetFile.getAbsolutePath() +
-                        "'. Using default stylesheet instead. Due to: " + 
e.getMessage());
+                LOGGER.log(WARNING, "Unable to copy specified stylesheet 
''{0}''. Using default stylesheet instead. Due to: {1}",
+                        styleSheetFile.getAbsolutePath(), e.getMessage());
             }
         }
     }
diff --git 
a/subprojects/groovy-ant/src/test/groovy/org/codehaus/groovy/ant/GroovycTest.java
 
b/subprojects/groovy-ant/src/test/groovy/org/codehaus/groovy/ant/GroovycTest.java
index 15b7653401..2b6da8b2dc 100644
--- 
a/subprojects/groovy-ant/src/test/groovy/org/codehaus/groovy/ant/GroovycTest.java
+++ 
b/subprojects/groovy-ant/src/test/groovy/org/codehaus/groovy/ant/GroovycTest.java
@@ -25,7 +25,6 @@ import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
@@ -34,6 +33,10 @@ import java.io.IOException;
 import java.io.PrintStream;
 import java.net.URISyntaxException;
 import java.nio.file.Paths;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
 import java.util.regex.Pattern;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -243,24 +246,35 @@ final class GroovycTest {
 
     @Test
     void testGroovyc_Joint_NoFork_NestedCompilerArg_WithGroovyClasspath() {
-        // capture ant's output so we can verify the effect of passing 
compilerarg to javac
-        ByteArrayOutputStream allOutput = new ByteArrayOutputStream();
+        // Capture javac warnings via JUL handler — JavacJavaCompiler logs via 
System.Logger
+        // which defaults to JUL backend
+        StringBuilder logOutput = new StringBuilder();
+        String loggerName = 
"org.codehaus.groovy.tools.javac.JavacJavaCompiler";
+        Logger julLogger = Logger.getLogger(loggerName);
+        Level originalLevel = julLogger.getLevel();
+        julLogger.setLevel(Level.ALL);
+        Handler handler = new Handler() {
+            @Override public void publish(LogRecord record) { 
logOutput.append(record.getMessage()); }
+            @Override public void flush() {}
+            @Override public void close() {}
+        };
+        handler.setLevel(Level.ALL);
+        julLogger.addHandler(handler);
 
-        PrintStream out = System.out;
-        System.setOut(new PrintStream(allOutput));
         try {
             ensureNotPresent("IncorrectGenericsUsage");
             
project.executeTarget("Groovyc_Joint_NoFork_NestedCompilerArg_WithGroovyClasspath");
             ensurePresent("IncorrectGenericsUsage");
 
-            String antOutput = 
adjustOutputToHandleOpenJDKJavacOutputDifference(allOutput.toString());
+            String antOutput = 
adjustOutputToHandleOpenJDKJavacOutputDifference(logOutput.toString());
             // verify if passing -Xlint in compilerarg had its effect
             Pattern p = Pattern.compile(".*?found[ ]*:[ 
]*java.util.ArrayList.*", Pattern.DOTALL);
             assertTrue(p.matcher(antOutput).matches(), "Expected line 1 not 
found in ant output");
             p = Pattern.compile(".*?required[ ]*:[ 
]*java.util.ArrayList<java.lang.String>.*", Pattern.DOTALL);
             assertTrue(p.matcher(antOutput).matches(), "Expected line 2 not 
found in ant output");
         } finally {
-            System.setOut(out);
+            julLogger.removeHandler(handler);
+            julLogger.setLevel(originalLevel);
         }
     }
 
diff --git 
a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleTextEditor.java
 
b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleTextEditor.java
index 03e0f7978a..fed406c621 100644
--- 
a/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleTextEditor.java
+++ 
b/subprojects/groovy-console/src/main/groovy/groovy/console/ui/ConsoleTextEditor.java
@@ -55,10 +55,13 @@ import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.util.prefs.Preferences;
 
+import static java.lang.System.Logger.Level.WARNING;
+
 /**
  * Component which provides a styled editor for the console.
  */
 public class ConsoleTextEditor extends JScrollPane {
+    private static final System.Logger LOGGER = 
System.getLogger(ConsoleTextEditor.class.getName());
     private static final long serialVersionUID = -3582625263676326887L;
     private static final Preferences PREFERENCES = 
Preferences.userNodeForPackage(Console.class);
     private static final String PREFERENCE_FONT_SIZE = "fontSize";
@@ -104,7 +107,7 @@ public class ConsoleTextEditor extends JScrollPane {
             try {
                 startingY = textEditor.modelToView(start).y + fontHeight - 
fontDesc;
             } catch (BadLocationException e1) {
-                System.err.println(e1.getMessage());
+                LOGGER.log(WARNING, e1.getMessage());
             }
             g.setFont(f);
             for (int line = startline, y = startingY; line <= endline; y += 
fontHeight, line++) {
diff --git 
a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/FileOutputTool.java
 
b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/FileOutputTool.java
index 3d07555b22..70e0514ba5 100644
--- 
a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/FileOutputTool.java
+++ 
b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/FileOutputTool.java
@@ -26,7 +26,11 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
+import static java.lang.System.Logger.Level.WARNING;
+
 public class FileOutputTool implements OutputTool {
+
+    private static final System.Logger LOGGER = 
System.getLogger(FileOutputTool.class.getName());
     @Override
     public void makeOutputArea(String filename) {
         Path path = Paths.get(filename);
@@ -36,7 +40,7 @@ public class FileOutputTool implements OutputTool {
         try {
             Files.createDirectories(path);
         } catch (IOException e) {
-            System.err.println("Unable to create directory '" + filename + "' 
due to '" + e.getMessage() + "'; attempting to continue...");
+            LOGGER.log(WARNING, "Unable to create directory ''{0}'' due to 
''{1}''; attempting to continue...", filename, e.getMessage());
         }
     }
 
@@ -48,7 +52,7 @@ public class FileOutputTool implements OutputTool {
             try {
                 Files.createDirectories(path);
             } catch (IOException e) {
-                System.err.println("Unable to create parent directory '" + 
path + "' due to '" + e.getMessage() + "'; attempting to continue...");
+                LOGGER.log(WARNING, "Unable to create parent directory ''{0}'' 
due to ''{1}''; attempting to continue...", path, e.getMessage());
             }
         }
         ResourceGroovyMethods.write(file, text, charset, true);
diff --git 
a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/GroovyDocTemplateEngine.java
 
b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/GroovyDocTemplateEngine.java
index f763fdc728..75b201a925 100644
--- 
a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/GroovyDocTemplateEngine.java
+++ 
b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/GroovyDocTemplateEngine.java
@@ -40,10 +40,15 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
+import static java.lang.System.Logger.Level.ERROR;
+import static java.lang.System.Logger.Level.WARNING;
+
 /**
  * Process Groovydoc templates.
  */
 public class GroovyDocTemplateEngine {
+
+    private static final System.Logger LOGGER = 
System.getLogger(GroovyDocTemplateEngine.class.getName());
     private final TemplateEngine engine;
     private final ResourceManager resourceManager;
     private final Properties properties;
@@ -89,8 +94,8 @@ public class GroovyDocTemplateEngine {
             binding.put("props", properties);
             templateWithBindingApplied = 
t.make(binding).writeTo(reasonableSizeWriter()).toString();
         } catch (Exception e) {
-            System.out.println("Error processing class template for: " + 
classDoc.getFullPathName());
-            e.printStackTrace();
+            LOGGER.log(ERROR, "Error processing class template for: {0}", 
classDoc.getFullPathName());
+            LOGGER.log(ERROR, "Template error", e);
         }
         return templateWithBindingApplied;
     }
@@ -112,8 +117,8 @@ public class GroovyDocTemplateEngine {
             binding.put("props", properties);
             templateWithBindingApplied = t.make(binding).toString();
         } catch (Exception e) {
-            System.out.println("Error processing package template for: " + 
packageDoc.name());
-            e.printStackTrace();
+            LOGGER.log(ERROR, "Error processing package template for: {0}", 
packageDoc.name());
+            LOGGER.log(ERROR, "Template error", e);
         }
         return templateWithBindingApplied;
     }
@@ -131,8 +136,8 @@ public class GroovyDocTemplateEngine {
             binding.put("props", properties);
             templateWithBindingApplied = t.make(binding).toString();
         } catch (Exception e) {
-            System.out.println("Error processing root doc template");
-            e.printStackTrace();
+            LOGGER.log(ERROR, "Error processing root doc template");
+            LOGGER.log(ERROR, "Template error", e);
         }
         return templateWithBindingApplied;
     }
@@ -157,9 +162,9 @@ public class GroovyDocTemplateEngine {
                 outputStream = Files.newOutputStream(Paths.get(destFileName));
                 IOGroovyMethods.leftShift(outputStream, inputStream);
             } catch (IOException e) {
-                System.err.println("Resource " + template + " skipped due to: 
" + e.getMessage());
+                LOGGER.log(WARNING, "Resource {0} skipped due to: {1}", 
template, e.getMessage());
             } catch (NullPointerException e) {
-                System.err.println("Resource " + template + " not found so 
skipped");
+                LOGGER.log(WARNING, "Resource {0} not found so skipped", 
template);
             } finally {
                 DefaultGroovyMethodsSupport.closeQuietly(outputStream);
             }
diff --git 
a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/GroovyRootDocBuilder.java
 
b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/GroovyRootDocBuilder.java
index 3fc2f47ef5..1c36ecee37 100644
--- 
a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/GroovyRootDocBuilder.java
+++ 
b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/GroovyRootDocBuilder.java
@@ -36,6 +36,7 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.regex.Pattern;
 
+import static java.lang.System.Logger.Level.WARNING;
 import static 
org.codehaus.groovy.tools.groovydoc.SimpleGroovyClassDoc.CODE_REGEX;
 import static 
org.codehaus.groovy.tools.groovydoc.SimpleGroovyClassDoc.LINK_REGEX;
 import static 
org.codehaus.groovy.tools.groovydoc.SimpleGroovyClassDoc.TAG_REGEX;
@@ -44,6 +45,7 @@ import static 
org.codehaus.groovy.tools.groovydoc.SimpleGroovyClassDoc.TAG_REGEX
  *  todo: order methods alphabetically (implement compareTo enough?)
  */
 public class GroovyRootDocBuilder {
+    private static final System.Logger LOGGER = 
System.getLogger(GroovyRootDocBuilder.class.getName());
     private final Logger log = Logger.create(GroovyRootDocBuilder.class);
     private static final char FS = '/';
     private final List<LinkArgument> links;
@@ -96,7 +98,7 @@ public class GroovyRootDocBuilder {
                 String content = ResourceGroovyMethods.getText(new File(path));
                 calcThenSetOverviewDescription(content);
             } catch (IOException e) {
-                System.err.println("Unable to load overview file: " + 
e.getMessage());
+                LOGGER.log(WARNING, "Unable to load overview file: {0}", 
e.getMessage());
             }
         }
     }
diff --git 
a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/antlr4/GroovyDocParser.java
 
b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/antlr4/GroovyDocParser.java
index eaaa807f0f..c507ff79fc 100644
--- 
a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/antlr4/GroovyDocParser.java
+++ 
b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/antlr4/GroovyDocParser.java
@@ -40,7 +40,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
+import static java.lang.System.Logger.Level.WARNING;
+
 public class GroovyDocParser implements GroovyDocParserI {
+
+    private static final System.Logger LOGGER = 
System.getLogger(GroovyDocParser.class.getName());
+
     private final List<LinkArgument> links;
     private final Properties properties;
     private final Logger log = Logger.create(GroovyDocParser.class);
@@ -68,11 +73,11 @@ public class GroovyDocParser implements GroovyDocParserI {
         GroovydocJavaVisitor visitor = new GroovydocJavaVisitor(packagePath, 
links);
         try {
             visitor.visit(StaticJavaParser.parse(src), null);
-        } catch(Throwable t) {
-            System.err.println("Attempting to ignore error parsing Java source 
file: " + packagePath + "/" + file);
-            System.err.println("Consider reporting the error to the Groovy 
project: https://issues.apache.org/jira/browse/GROOVY";);
-            System.err.println("... or directly to the JavaParser project: 
https://github.com/javaparser/javaparser/issues";);
-            System.err.println("Error: " + t.getMessage());
+        } catch (Throwable t) {
+            LOGGER.log(WARNING, "Attempting to ignore error parsing Java 
source file: {0}/{1}", packagePath, file);
+            LOGGER.log(WARNING, "Consider reporting the error to the Groovy 
project: https://issues.apache.org/jira/browse/GROOVY";);
+            LOGGER.log(WARNING, "... or directly to the JavaParser project: 
https://github.com/javaparser/javaparser/issues";);
+            LOGGER.log(WARNING, "Error: {0}", t.getMessage());
         }
         return visitor.getGroovyClassDocs();
     }
@@ -98,7 +103,7 @@ public class GroovyDocParser implements GroovyDocParserI {
                     case "INSTRUCTION_SELECTION": phase = 6; break;
                     case "CLASS_GENERATION": phase = 7; break;
                     default:
-                        System.err.println("Ignoring unrecognised or 
unsuitable phase and keeping default");
+                        LOGGER.log(WARNING, "Ignoring unrecognised or 
unsuitable phase and keeping default");
                 }
             }
         }
diff --git 
a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java
 
b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java
index 782ebfa3c2..3033c0142c 100644
--- 
a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java
+++ 
b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java
@@ -27,8 +27,6 @@ import org.codehaus.groovy.groovydoc.GroovyRootDoc;
 import org.codehaus.groovy.runtime.StringGroovyMethods;
 import 
org.codehaus.groovy.tools.groovydoc.gstringTemplates.GroovyDocTemplateInfo;
 
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -1042,28 +1040,13 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
         final String base = 
"org/codehaus/groovy/tools/groovydoc/testfiles/generics";
 
-        PrintStream originalSystemErr = System.err;
-        ByteArrayOutputStream systemErr = new ByteArrayOutputStream();
-        try {
-            System.setErr(new PrintStream(systemErr));
-            htmlTool.add(Arrays.asList(
-                base + "/Java.java"
-            ));
-        }
-        finally {
-            System.setErr(originalSystemErr);
-        }
-        final String errorMessage = systemErr.toString();
-        System.err.println(errorMessage);
+        htmlTool.add(Arrays.asList(base + "/Java.java"));
 
         final MockOutputTool output = new MockOutputTool();
         htmlTool.renderToOutput(output, MOCK_DIR);
 
         final String javadoc = output.getText(MOCK_DIR + "/" + base + 
"/Java.html");
         assertNull("Javadoc should be null since language level is not 
supported", javadoc);
-
-        assertTrue("Expected to find Java file in error message", 
errorMessage.contains("org/codehaus/groovy/tools/groovydoc/testfiles/generics/Java.java"));
-        assertTrue("Expected to find language level not supported", 
errorMessage.contains("Pay attention that this feature is supported starting 
from"));
     }
 
     public void testLanguageLevelSupported() throws Exception {
@@ -1071,27 +1054,13 @@ public class GroovyDocToolTest extends GroovyTestCase {
 
         final String base = 
"org/codehaus/groovy/tools/groovydoc/testfiles/generics";
 
-        PrintStream originalSystemErr = System.err;
-        ByteArrayOutputStream systemErr = new ByteArrayOutputStream();
-        try {
-            System.setErr(new PrintStream(systemErr));
-            htmlTool.add(Arrays.asList(
-                base + "/Java.java"
-            ));
-        }
-        finally {
-            System.setErr(originalSystemErr);
-        }
-        final String errorMessage = systemErr.toString();
-        System.err.println(errorMessage);
+        htmlTool.add(Arrays.asList(base + "/Java.java"));
 
         final MockOutputTool output = new MockOutputTool();
         htmlTool.renderToOutput(output, MOCK_DIR);
 
         final String javadoc = output.getText(MOCK_DIR + "/" + base + 
"/Java.html");
         assertNotNull("Javadoc should not be null since language level is 
supported", javadoc);
-
-        assertTrue("Expected no error output", errorMessage.isEmpty());
     }
 
     public void testJavaGenericsTitle() throws Exception {
diff --git 
a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Exceptions.java
 
b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Exceptions.java
index aece9b95b6..254e2b8db5 100644
--- 
a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Exceptions.java
+++ 
b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Exceptions.java
@@ -24,8 +24,12 @@ import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.util.Collections;
 
+import static java.lang.System.Logger.Level.ERROR;
+
 public class Exceptions {
 
+    private static final System.Logger LOGGER = 
System.getLogger(Exceptions.class.getName());
+
     public static boolean die() {
         throw new JsonInternalException("died");
     }
@@ -128,12 +132,10 @@ public class Exceptions {
 
         @Override
         public void printStackTrace() {
-            System.err.println(this.getMessage());
+            LOGGER.log(ERROR, this.getMessage());
 
             if (getCause() != null) {
-                System.err.println("This Exception was wrapped, the original 
exception\n" +
-                        "stack trace is:\n");
-                getCause().printStackTrace();
+                LOGGER.log(ERROR, "This Exception was wrapped, the original 
exception stack trace is:", getCause());
             } else {
                 super.printStackTrace();
             }
diff --git 
a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Sys.java
 
b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Sys.java
index 1ec1040903..353fc02876 100644
--- 
a/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Sys.java
+++ 
b/subprojects/groovy-json/src/main/java/org/apache/groovy/json/internal/Sys.java
@@ -22,8 +22,12 @@ import java.math.BigDecimal;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import static java.lang.System.Logger.Level.WARNING;
+
 class Sys {
 
+    private static final System.Logger LOGGER = 
System.getLogger(Sys.class.getName());
+
     private static final boolean is1_8OrLater;
     private static final boolean is1_7;
     private static final boolean is1_8;
@@ -48,8 +52,7 @@ class Sys {
                     v = new BigDecimal("1.9");
                 }
             } catch (Exception ex) {
-                ex.printStackTrace();
-                System.err.println("Unable to determine build number or 
version");
+                LOGGER.log(WARNING, "Unable to determine build number or 
version", ex);
             }
         } else if ("1.8.0".equals(sversion)) {
             v = new BigDecimal("1.8");
diff --git 
a/subprojects/groovy-servlet/src/main/java/groovy/servlet/GroovyServlet.java 
b/subprojects/groovy-servlet/src/main/java/groovy/servlet/GroovyServlet.java
index 251ea687e8..282b41b6be 100644
--- a/subprojects/groovy-servlet/src/main/java/groovy/servlet/GroovyServlet.java
+++ b/subprojects/groovy-servlet/src/main/java/groovy/servlet/GroovyServlet.java
@@ -30,6 +30,8 @@ import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 
+import static java.lang.System.Logger.Level.ERROR;
+
 /**
  * This servlet will run Groovy scripts as Groovlets.  Groovlets are scripts
  * with these objects implicit in their scope:
@@ -73,6 +75,8 @@ import java.io.IOException;
  */
 public class GroovyServlet extends AbstractHttpServlet {
 
+    private static final System.Logger LOGGER = 
System.getLogger(GroovyServlet.class.getName());
+
     /**
      * The script engine executing the Groovy scripts for this servlet
      */
@@ -139,8 +143,8 @@ public class GroovyServlet extends AbstractHttpServlet {
                 if (runtimeException.getStackTrace().length > 0)
                     
error.append(runtimeException.getStackTrace()[0].toString());
                 servletContext.log(error.toString());
-                System.err.println(error);
-                runtimeException.printStackTrace(System.err);
+                LOGGER.log(ERROR, error.toString());
+                LOGGER.log(ERROR, "Script processing failed", 
runtimeException);
                 
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 
error.toString());
                 return;
             }
@@ -150,7 +154,7 @@ public class GroovyServlet extends AbstractHttpServlet {
             if (e instanceof ResourceException) {
                 error.append(" Script not found, sending 404.");
                 servletContext.log(error.toString());
-                System.err.println(error);
+                LOGGER.log(ERROR, error.toString());
                 response.sendError(HttpServletResponse.SC_NOT_FOUND);
                 return;
             }
@@ -162,8 +166,8 @@ public class GroovyServlet extends AbstractHttpServlet {
             if (e.getStackTrace().length > 0)
                 error.append(e.getStackTrace()[0].toString());
             servletContext.log(e.toString());
-            System.err.println(e.toString());
-            runtimeException.printStackTrace(System.err);
+            LOGGER.log(ERROR, e.toString());
+            LOGGER.log(ERROR, "Internal error", runtimeException);
             response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 
e.toString());
         }
     }
diff --git 
a/subprojects/groovy-swing/src/main/java/groovy/swing/table/TableSorter.java 
b/subprojects/groovy-swing/src/main/java/groovy/swing/table/TableSorter.java
index 5a3e089c1b..84cd20c6fe 100644
--- a/subprojects/groovy-swing/src/main/java/groovy/swing/table/TableSorter.java
+++ b/subprojects/groovy-swing/src/main/java/groovy/swing/table/TableSorter.java
@@ -28,6 +28,8 @@ import java.awt.event.MouseEvent;
 import java.util.Date;
 import java.util.Vector;
 
+import static java.lang.System.Logger.Level.WARNING;
+
 /**
  * A sorter for TableModels.
  * <p>
@@ -45,6 +47,7 @@ import java.util.Vector;
  * function returns 0 to denote that they are equivalent.
  */
 public class TableSorter extends TableMap {
+    private static final System.Logger LOGGER = 
System.getLogger(TableSorter.class.getName());
     private static final int[] EMPTY_INT_ARRAY = new int[0];
     int[] indexes;
     Vector<Integer> sortingColumns = new Vector<>();
@@ -185,7 +188,7 @@ public class TableSorter extends TableMap {
 
     public void checkModel() {
         if (indexes.length != model.getRowCount()) {
-            System.err.println("Sorter not informed of a change in model.");
+            LOGGER.log(WARNING, "Sorter not informed of a change in model");
         }
     }
 
diff --git 
a/subprojects/groovy-test-junit5/src/main/java/groovy/junit5/plugin/JUnit5Runner.java
 
b/subprojects/groovy-test-junit5/src/main/java/groovy/junit5/plugin/JUnit5Runner.java
index 53e0b7d369..0a6d2c910a 100644
--- 
a/subprojects/groovy-test-junit5/src/main/java/groovy/junit5/plugin/JUnit5Runner.java
+++ 
b/subprojects/groovy-test-junit5/src/main/java/groovy/junit5/plugin/JUnit5Runner.java
@@ -28,11 +28,15 @@ import java.lang.reflect.Method;
 import java.util.HashSet;
 import java.util.Set;
 
+import static java.lang.System.Logger.Level.WARNING;
+
 /**
  * Integration code for running JUnit5 tests in Groovy.
  */
 public class JUnit5Runner implements GroovyRunner {
 
+    private static final System.Logger LOGGER = 
System.getLogger(JUnit5Runner.class.getName());
+
     /**
      * Utility method to check via reflection if the parsed class appears to 
be a JUnit5
      * test, i.e. checks whether it appears to be using the relevant 
annotations.
@@ -117,7 +121,7 @@ public class JUnit5Runner implements GroovyRunner {
                 
loader.loadClass("org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder");
             } catch (ClassNotFoundException ignored) {
                 // subsequent steps will bomb out but try to give some more 
friendly information first
-                System.err.println("WARNING: Required dependency: 
org.junit.platform:junit-platform-launcher doesn't appear to be on the 
classpath");
+                LOGGER.log(WARNING, "Required dependency: 
org.junit.platform:junit-platform-launcher doesn''t appear to be on the 
classpath");
             }
             Class<?> helper = 
loader.loadClass("groovy.junit5.plugin.GroovyJUnitRunnerHelper");
             Throwable ifFailed = (Throwable) 
InvokerHelper.invokeStaticMethod(helper, "execute", new Object[]{scriptClass});
diff --git 
a/subprojects/groovy-test/src/main/java/groovy/test/GroovyTestSuite.java 
b/subprojects/groovy-test/src/main/java/groovy/test/GroovyTestSuite.java
index 93517ef765..6b2e4edf11 100644
--- a/subprojects/groovy-test/src/main/java/groovy/test/GroovyTestSuite.java
+++ b/subprojects/groovy-test/src/main/java/groovy/test/GroovyTestSuite.java
@@ -28,6 +28,8 @@ import org.apache.groovy.test.ScriptTestAdapter;
 
 import java.io.File;
 
+import static java.lang.System.Logger.Level.INFO;
+
 /**
  * A TestSuite which will run a Groovy unit test case inside any Java IDE
  * either as a unit test case or as an application.
@@ -46,6 +48,8 @@ import java.io.File;
  */
 public class GroovyTestSuite extends TestSuite {
 
+    private static final System.Logger LOGGER = 
System.getLogger(GroovyTestSuite.class.getName());
+
     protected static String file = null;
 
     protected final GroovyClassLoader loader = new 
GroovyClassLoader(GroovyTestSuite.class.getClassLoader());
@@ -72,7 +76,7 @@ public class GroovyTestSuite extends TestSuite {
         if (fileName == null) {
             throw new RuntimeException("No filename given in the 'test' system 
property so cannot run a Groovy unit test");
         }
-        System.out.println("Compiling: " + fileName);
+        LOGGER.log(INFO, "Compiling: {0}", fileName);
         Class<?> type = compile(fileName);
         String[] args = {};
         if (TestCase.class.isAssignableFrom(type)) {

Reply via email to