From e999300158c5461c8994219a1fa943b4d7ba3291 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sun, 15 Feb 2026 16:22:15 -0500 Subject: [PATCH 1/6] fix(deps): upgrade slf4j and logback --- .../ant/logging/AntLoggerAdapter.java | 339 +++++++++++++----- .../ant/logging/AntLoggerFactory.java | 13 +- .../ant/logging/AntSlf4jServiceProvider.java | 69 ++++ .../ant/logging/AntTaskHolder.java | 50 +++ .../owasp/dependencycheck/taskdefs/Check.java | 4 +- .../owasp/dependencycheck/taskdefs/Purge.java | 4 +- .../dependencycheck/taskdefs/Update.java | 4 +- .../org/slf4j/impl/StaticLoggerBinder.java | 115 ------ .../java/org/slf4j/impl/package-info.java | 4 - .../org.slf4j.spi.SLF4JServiceProvider | 1 + pom.xml | 4 +- 11 files changed, 386 insertions(+), 221 deletions(-) create mode 100644 ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProvider.java create mode 100644 ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntTaskHolder.java delete mode 100644 ant/src/main/java/org/slf4j/impl/StaticLoggerBinder.java delete mode 100644 ant/src/main/java/org/slf4j/impl/package-info.java create mode 100644 ant/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider diff --git a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java index d131ece4be7..db0bbc2f8c7 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java +++ b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java @@ -19,91 +19,120 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; +import org.slf4j.Logger; +import org.slf4j.Marker; import org.slf4j.helpers.FormattingTuple; -import org.slf4j.helpers.MarkerIgnoringBase; import org.slf4j.helpers.MessageFormatter; /** * An instance of {@link org.slf4j.Logger} which simply calls the log method on - * the delegate Ant task. + * the current Ant task obtained from {@link AntTaskHolder}. * * @author colezlaw */ -public class AntLoggerAdapter extends MarkerIgnoringBase { +public class AntLoggerAdapter implements Logger { /** * The serial version UID for serialization. */ private static final long serialVersionUID = -8546294566287970709L; - /** - * A reference to the Ant task used for logging. - */ - private transient Task task; /** - * Constructs an Ant Logger Adapter. - * - * @param task the Ant Task to use for logging + * The logger name. */ - public AntLoggerAdapter(Task task) { - super(); - this.task = task; + private static final String NAME = "dependency-check-ant"; + + @Override + public String getName() { + return NAME; } - /** - * Sets the current Ant task to use for logging. - * - * @param task the Ant task to use for logging - */ - public void setTask(Task task) { - this.task = task; + private Task task() { + return AntTaskHolder.getTask(); } + // --- TRACE --- + @Override public boolean isTraceEnabled() { - // Might be a more efficient way to do this, but Ant doesn't enable or disable - // various levels globally - it just fires things at registered Listeners. return true; } @Override public void trace(String msg) { - if (task != null) { - task.log(msg, Project.MSG_VERBOSE); + final Task t = task(); + if (t != null) { + t.log(msg, Project.MSG_VERBOSE); } } @Override public void trace(String format, Object arg) { - if (task != null) { + final Task t = task(); + if (t != null) { final FormattingTuple tp = MessageFormatter.format(format, arg); - task.log(tp.getMessage(), Project.MSG_VERBOSE); + t.log(tp.getMessage(), Project.MSG_VERBOSE); } } @Override public void trace(String format, Object arg1, Object arg2) { - if (task != null) { + final Task t = task(); + if (t != null) { final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2); - task.log(tp.getMessage(), Project.MSG_VERBOSE); + t.log(tp.getMessage(), Project.MSG_VERBOSE); } } @Override public void trace(String format, Object... arguments) { - if (task != null) { - final FormattingTuple tp = MessageFormatter.format(format, arguments); - task.log(tp.getMessage(), Project.MSG_VERBOSE); + final Task t = task(); + if (t != null) { + final FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments); + t.log(tp.getMessage(), Project.MSG_VERBOSE); } } @Override - public void trace(String msg, Throwable t) { - if (task != null) { - task.log(msg, t, Project.MSG_VERBOSE); + public void trace(String msg, Throwable throwable) { + final Task t = task(); + if (t != null) { + t.log(msg, throwable, Project.MSG_VERBOSE); } } + @Override + public boolean isTraceEnabled(Marker marker) { + return isTraceEnabled(); + } + + @Override + public void trace(Marker marker, String msg) { + trace(msg); + } + + @Override + public void trace(Marker marker, String format, Object arg) { + trace(format, arg); + } + + @Override + public void trace(Marker marker, String format, Object arg1, Object arg2) { + trace(format, arg1, arg2); + } + + @Override + public void trace(Marker marker, String format, Object... argArray) { + trace(format, argArray); + } + + @Override + public void trace(Marker marker, String msg, Throwable throwable) { + trace(msg, throwable); + } + + // --- DEBUG --- + @Override public boolean isDebugEnabled() { return true; @@ -111,42 +140,79 @@ public boolean isDebugEnabled() { @Override public void debug(String msg) { - if (task != null) { - task.log(msg, Project.MSG_DEBUG); + final Task t = task(); + if (t != null) { + t.log(msg, Project.MSG_DEBUG); } } @Override public void debug(String format, Object arg) { - if (task != null) { + final Task t = task(); + if (t != null) { final FormattingTuple tp = MessageFormatter.format(format, arg); - task.log(tp.getMessage(), Project.MSG_DEBUG); + t.log(tp.getMessage(), Project.MSG_DEBUG); } } @Override public void debug(String format, Object arg1, Object arg2) { - if (task != null) { + final Task t = task(); + if (t != null) { final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2); - task.log(tp.getMessage(), Project.MSG_DEBUG); + t.log(tp.getMessage(), Project.MSG_DEBUG); } } @Override public void debug(String format, Object... arguments) { - if (task != null) { - final FormattingTuple tp = MessageFormatter.format(format, arguments); - task.log(tp.getMessage(), Project.MSG_DEBUG); + final Task t = task(); + if (t != null) { + final FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments); + t.log(tp.getMessage(), Project.MSG_DEBUG); } } @Override - public void debug(String msg, Throwable t) { - if (task != null) { - task.log(msg, t, Project.MSG_DEBUG); + public void debug(String msg, Throwable throwable) { + final Task t = task(); + if (t != null) { + t.log(msg, throwable, Project.MSG_DEBUG); } } + @Override + public boolean isDebugEnabled(Marker marker) { + return isDebugEnabled(); + } + + @Override + public void debug(Marker marker, String msg) { + debug(msg); + } + + @Override + public void debug(Marker marker, String format, Object arg) { + debug(format, arg); + } + + @Override + public void debug(Marker marker, String format, Object arg1, Object arg2) { + debug(format, arg1, arg2); + } + + @Override + public void debug(Marker marker, String format, Object... arguments) { + debug(format, arguments); + } + + @Override + public void debug(Marker marker, String msg, Throwable throwable) { + debug(msg, throwable); + } + + // --- INFO --- + @Override public boolean isInfoEnabled() { return true; @@ -154,42 +220,79 @@ public boolean isInfoEnabled() { @Override public void info(String msg) { - if (task != null) { - task.log(msg, Project.MSG_INFO); + final Task t = task(); + if (t != null) { + t.log(msg, Project.MSG_INFO); } } @Override public void info(String format, Object arg) { - if (task != null) { + final Task t = task(); + if (t != null) { final FormattingTuple tp = MessageFormatter.format(format, arg); - task.log(tp.getMessage(), Project.MSG_INFO); + t.log(tp.getMessage(), Project.MSG_INFO); } } @Override public void info(String format, Object arg1, Object arg2) { - if (task != null) { + final Task t = task(); + if (t != null) { final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2); - task.log(tp.getMessage(), Project.MSG_INFO); + t.log(tp.getMessage(), Project.MSG_INFO); } } @Override public void info(String format, Object... arguments) { - if (task != null) { - final FormattingTuple tp = MessageFormatter.format(format, arguments); - task.log(tp.getMessage(), Project.MSG_INFO); + final Task t = task(); + if (t != null) { + final FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments); + t.log(tp.getMessage(), Project.MSG_INFO); } } @Override - public void info(String msg, Throwable t) { - if (task != null) { - task.log(msg, t, Project.MSG_INFO); + public void info(String msg, Throwable throwable) { + final Task t = task(); + if (t != null) { + t.log(msg, throwable, Project.MSG_INFO); } } + @Override + public boolean isInfoEnabled(Marker marker) { + return isInfoEnabled(); + } + + @Override + public void info(Marker marker, String msg) { + info(msg); + } + + @Override + public void info(Marker marker, String format, Object arg) { + info(format, arg); + } + + @Override + public void info(Marker marker, String format, Object arg1, Object arg2) { + info(format, arg1, arg2); + } + + @Override + public void info(Marker marker, String format, Object... arguments) { + info(format, arguments); + } + + @Override + public void info(Marker marker, String msg, Throwable throwable) { + info(msg, throwable); + } + + // --- WARN --- + @Override public boolean isWarnEnabled() { return true; @@ -197,42 +300,79 @@ public boolean isWarnEnabled() { @Override public void warn(String msg) { - if (task != null) { - task.log(msg, Project.MSG_WARN); + final Task t = task(); + if (t != null) { + t.log(msg, Project.MSG_WARN); } } @Override public void warn(String format, Object arg) { - if (task != null) { + final Task t = task(); + if (t != null) { final FormattingTuple tp = MessageFormatter.format(format, arg); - task.log(tp.getMessage(), Project.MSG_WARN); + t.log(tp.getMessage(), Project.MSG_WARN); } } @Override public void warn(String format, Object... arguments) { - if (task != null) { - final FormattingTuple tp = MessageFormatter.format(format, arguments); - task.log(tp.getMessage(), Project.MSG_WARN); + final Task t = task(); + if (t != null) { + final FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments); + t.log(tp.getMessage(), Project.MSG_WARN); } } @Override public void warn(String format, Object arg1, Object arg2) { - if (task != null) { + final Task t = task(); + if (t != null) { final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2); - task.log(tp.getMessage(), Project.MSG_WARN); + t.log(tp.getMessage(), Project.MSG_WARN); } } @Override - public void warn(String msg, Throwable t) { - if (task != null) { - task.log(msg, t, Project.MSG_WARN); + public void warn(String msg, Throwable throwable) { + final Task t = task(); + if (t != null) { + t.log(msg, throwable, Project.MSG_WARN); } } + @Override + public boolean isWarnEnabled(Marker marker) { + return isWarnEnabled(); + } + + @Override + public void warn(Marker marker, String msg) { + warn(msg); + } + + @Override + public void warn(Marker marker, String format, Object arg) { + warn(format, arg); + } + + @Override + public void warn(Marker marker, String format, Object arg1, Object arg2) { + warn(format, arg1, arg2); + } + + @Override + public void warn(Marker marker, String format, Object... arguments) { + warn(format, arguments); + } + + @Override + public void warn(Marker marker, String msg, Throwable throwable) { + warn(msg, throwable); + } + + // --- ERROR --- + @Override public boolean isErrorEnabled() { return true; @@ -240,39 +380,74 @@ public boolean isErrorEnabled() { @Override public void error(String msg) { - if (task != null) { - task.log(msg, Project.MSG_ERR); + final Task t = task(); + if (t != null) { + t.log(msg, Project.MSG_ERR); } } @Override public void error(String format, Object arg) { - if (task != null) { + final Task t = task(); + if (t != null) { final FormattingTuple tp = MessageFormatter.format(format, arg); - task.log(tp.getMessage(), Project.MSG_ERR); + t.log(tp.getMessage(), Project.MSG_ERR); } } @Override public void error(String format, Object arg1, Object arg2) { - if (task != null) { + final Task t = task(); + if (t != null) { final FormattingTuple tp = MessageFormatter.format(format, arg1, arg2); - task.log(tp.getMessage(), Project.MSG_ERR); + t.log(tp.getMessage(), Project.MSG_ERR); } } @Override public void error(String format, Object... arguments) { - if (task != null) { - final FormattingTuple tp = MessageFormatter.format(format, arguments); - task.log(tp.getMessage(), Project.MSG_ERR); + final Task t = task(); + if (t != null) { + final FormattingTuple tp = MessageFormatter.arrayFormat(format, arguments); + t.log(tp.getMessage(), Project.MSG_ERR); } } @Override - public void error(String msg, Throwable t) { - if (task != null) { - task.log(msg, t, Project.MSG_ERR); + public void error(String msg, Throwable throwable) { + final Task t = task(); + if (t != null) { + t.log(msg, throwable, Project.MSG_ERR); } } + + @Override + public boolean isErrorEnabled(Marker marker) { + return isErrorEnabled(); + } + + @Override + public void error(Marker marker, String msg) { + error(msg); + } + + @Override + public void error(Marker marker, String format, Object arg) { + error(format, arg); + } + + @Override + public void error(Marker marker, String format, Object arg1, Object arg2) { + error(format, arg1, arg2); + } + + @Override + public void error(Marker marker, String format, Object... arguments) { + error(format, arguments); + } + + @Override + public void error(Marker marker, String msg, Throwable throwable) { + error(msg, throwable); + } } diff --git a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerFactory.java b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerFactory.java index f5d10d5193e..070c85ebd7c 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerFactory.java +++ b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerFactory.java @@ -17,7 +17,6 @@ */ package org.owasp.dependencycheck.ant.logging; -import org.apache.tools.ant.Task; import org.slf4j.ILoggerFactory; import org.slf4j.Logger; @@ -31,17 +30,7 @@ public class AntLoggerFactory implements ILoggerFactory { /** * A reference to the Ant logger Adapter. */ - private final AntLoggerAdapter antLoggerAdapter; - - /** - * Constructs a new Ant Logger Factory. - * - * @param task the Ant task to use for logging - */ - public AntLoggerFactory(Task task) { - super(); - this.antLoggerAdapter = new AntLoggerAdapter(task); - } + private final AntLoggerAdapter antLoggerAdapter = new AntLoggerAdapter(); /** * Returns the Ant logger adapter. diff --git a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProvider.java b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProvider.java new file mode 100644 index 00000000000..418efe8b36e --- /dev/null +++ b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProvider.java @@ -0,0 +1,69 @@ +/* + * This file is part of dependency-check-ant. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 The OWASP Foundation. All Rights Reserved. + */ +package org.owasp.dependencycheck.ant.logging; + +import org.slf4j.ILoggerFactory; +import org.slf4j.IMarkerFactory; +import org.slf4j.helpers.BasicMarkerFactory; +import org.slf4j.helpers.NOPMDCAdapter; +import org.slf4j.spi.MDCAdapter; +import org.slf4j.spi.SLF4JServiceProvider; + +/** + * SLF4J 2.0 service provider for the dependency-check Ant integration. + * Replaces the old StaticLoggerBinder mechanism used in SLF4J 1.x. + */ +public class AntSlf4jServiceProvider implements SLF4JServiceProvider { + + /** + * Declare the version of the SLF4J API this implementation is compiled + * against. + */ + private static final String REQUESTED_API_VERSION = "2.0"; + + private ILoggerFactory loggerFactory; + private IMarkerFactory markerFactory; + private MDCAdapter mdcAdapter; + + @Override + public ILoggerFactory getLoggerFactory() { + return loggerFactory; + } + + @Override + public IMarkerFactory getMarkerFactory() { + return markerFactory; + } + + @Override + public MDCAdapter getMDCAdapter() { + return mdcAdapter; + } + + @Override + public String getRequestedApiVersion() { + return REQUESTED_API_VERSION; + } + + @Override + public void initialize() { + loggerFactory = new AntLoggerFactory(); + markerFactory = new BasicMarkerFactory(); + mdcAdapter = new NOPMDCAdapter(); + } +} diff --git a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntTaskHolder.java b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntTaskHolder.java new file mode 100644 index 00000000000..3b8ad175caf --- /dev/null +++ b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntTaskHolder.java @@ -0,0 +1,50 @@ +/* + * This file is part of dependency-check-ant. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 The OWASP Foundation. All Rights Reserved. + */ +package org.owasp.dependencycheck.ant.logging; + +import org.apache.tools.ant.Task; + +/** + * Holds a reference to the current Ant Task for logging. Replaces the old + * StaticLoggerBinder singleton pattern used with SLF4J 1.x. + */ +public final class AntTaskHolder { + + private static volatile Task task; + + private AntTaskHolder() { + } + + /** + * Sets the current Ant task to use for logging. + * + * @param t the Ant task + */ + public static void setTask(Task t) { + task = t; + } + + /** + * Returns the current Ant task. + * + * @return the Ant task, or null if not set + */ + public static Task getTask() { + return task; + } +} diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java index 3882743a3d0..cd74addae4b 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java +++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Check.java @@ -46,7 +46,7 @@ import org.owasp.dependencycheck.utils.Settings; import org.owasp.dependencycheck.utils.SeverityUtil; import org.owasp.dependencycheck.utils.scarf.TelemetryCollector; -import org.slf4j.impl.StaticLoggerBinder; +import org.owasp.dependencycheck.ant.logging.AntTaskHolder; //CSOFF: MethodCount /** @@ -517,7 +517,7 @@ public Check() { super(); // Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from // core end up coming through this tasks logger - StaticLoggerBinder.getSingleton().setTask(this); + AntTaskHolder.setTask(this); } /** diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java index 023087b8f7e..afa1aa65599 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java +++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java @@ -29,7 +29,7 @@ import org.owasp.dependencycheck.utils.Downloader; import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.Settings; -import org.slf4j.impl.StaticLoggerBinder; +import org.owasp.dependencycheck.ant.logging.AntTaskHolder; /** * An Ant task definition to execute dependency-check during an Ant build. @@ -65,7 +65,7 @@ public Purge() { // Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from // core end up coming through this tasks logger - StaticLoggerBinder.getSingleton().setTask(this); + AntTaskHolder.setTask(this); } public Settings getSettings() { diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java index 1cac8153188..9736dfc277e 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java +++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Update.java @@ -25,7 +25,7 @@ import org.owasp.dependencycheck.utils.Downloader; import org.owasp.dependencycheck.utils.InvalidSettingException; import org.owasp.dependencycheck.utils.Settings; -import org.slf4j.impl.StaticLoggerBinder; +import org.owasp.dependencycheck.ant.logging.AntTaskHolder; /** * An Ant task definition to execute dependency-check update. This will download @@ -222,7 +222,7 @@ public Update() { super(); // Call this before Dependency Check Core starts logging anything - this way, all SLF4J messages from // core end up coming through this tasks logger - StaticLoggerBinder.getSingleton().setTask(this); + AntTaskHolder.setTask(this); } /** diff --git a/ant/src/main/java/org/slf4j/impl/StaticLoggerBinder.java b/ant/src/main/java/org/slf4j/impl/StaticLoggerBinder.java deleted file mode 100644 index 683fd331fcf..00000000000 --- a/ant/src/main/java/org/slf4j/impl/StaticLoggerBinder.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is part of dependency-check-ant. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright (c) 2015 The OWASP Foundation. All Rights Reserved. - */ -package org.slf4j.impl; - -import org.apache.tools.ant.Task; -import org.owasp.dependencycheck.ant.logging.AntLoggerFactory; -import org.slf4j.ILoggerFactory; -import org.slf4j.spi.LoggerFactoryBinder; - -/** - * The binding of org.slf4j.LoggerFactory class with an actual instance of - * org.slf4j.ILoggerFactory is performed using information returned by this - * class. - * - * @author colezlaw - */ -//CSOFF: FinalClass -@SuppressWarnings({"squid:S1444", "squid:ClassVariableVisibilityCheck"}) -public class StaticLoggerBinder implements LoggerFactoryBinder { -//CSON: FinalClass - - /** - * The unique instance of this class - */ - private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); - /** - * Ant tasks have the log method we actually want to call. So we hang onto - * the task as a delegate - */ - private Task task = null; - - /** - * Declare the version of the SLF4J API this implementation is compiled - * against. The value of this filed is usually modified with each release. - */ - // to avoid constant folding by the compiler, this field must *not* be final - //CSOFF: StaticVariableName - //CSOFF: VisibilityModifier - @SuppressWarnings("squid:S3008") - public static String REQUESTED_API_VERSION = "1.7.12"; // final - //CSON: VisibilityModifier - //CSON: StaticVariableName - - /** - * The logger factory class string. - */ - private static final String LOGGER_FACTORY_CLASS = AntLoggerFactory.class.getName(); - - /** - * The ILoggerFactory instance returned by the {@link #getLoggerFactory} - * method should always be the same object - */ - private ILoggerFactory loggerFactory; - - /** - * Return the singleton of this class. - * - * @return the StaticLoggerBinder singleton - */ - public static StaticLoggerBinder getSingleton() { - return SINGLETON; - } - - /** - * Set the Task which will this is to log through. - * - * @param task the task through which to log - */ - public void setTask(Task task) { - this.task = task; - loggerFactory = new AntLoggerFactory(task); - } - - /** - * Constructs a new static logger binder. - */ - private StaticLoggerBinder() { - loggerFactory = new AntLoggerFactory(task); - } - - /** - * Returns the logger factory. - * - * @return the logger factory - */ - @Override - public ILoggerFactory getLoggerFactory() { - return loggerFactory; - } - - /** - * Returns the logger factory class string. - * - * @return the logger factory class string - */ - @Override - public String getLoggerFactoryClassStr() { - return LOGGER_FACTORY_CLASS; - } -} diff --git a/ant/src/main/java/org/slf4j/impl/package-info.java b/ant/src/main/java/org/slf4j/impl/package-info.java deleted file mode 100644 index c0c8e350575..00000000000 --- a/ant/src/main/java/org/slf4j/impl/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * This package contains the static binder for the slf4j-ant logger. - */ -package org.slf4j.impl; diff --git a/ant/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider b/ant/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider new file mode 100644 index 00000000000..efb8d4c5678 --- /dev/null +++ b/ant/src/main/resources/META-INF/services/org.slf4j.spi.SLF4JServiceProvider @@ -0,0 +1 @@ +org.owasp.dependencycheck.ant.logging.AntSlf4jServiceProvider diff --git a/pom.xml b/pom.xml index ee3771281d4..b01093d0da8 100644 --- a/pom.xml +++ b/pom.xml @@ -122,8 +122,8 @@ Copyright (c) 2012 - Jeremy Long 1.10.15 - 1.7.36 - 1.2.13 + 2.0.17 + 1.5.25 3.6.3 3.6.0 From a3dde1de81e8b9bf0541e7e828c0c9d06e536010 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Tue, 17 Feb 2026 10:49:47 -0500 Subject: [PATCH 2/6] fix: Apply suggestion from @jeremylong --- .../owasp/dependencycheck/ant/logging/AntLoggerAdapter.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java index db0bbc2f8c7..3dd195ea518 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java +++ b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java @@ -32,10 +32,6 @@ */ public class AntLoggerAdapter implements Logger { - /** - * The serial version UID for serialization. - */ - private static final long serialVersionUID = -8546294566287970709L; /** * The logger name. From e7d7fe5da916e32bde57a73ef56b8bcd88cbb5f6 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 07:54:32 -0500 Subject: [PATCH 3/6] fix: Make AntTaskHolder thread-safe using ThreadLocal (#8311) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jeremylong <862914+jeremylong@users.noreply.github.com> --- .../ant/logging/AntTaskHolder.java | 18 +++++++++++++++--- .../owasp/dependencycheck/taskdefs/Purge.java | 1 + 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntTaskHolder.java b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntTaskHolder.java index 3b8ad175caf..5cabdd7fc09 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntTaskHolder.java +++ b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntTaskHolder.java @@ -22,10 +22,13 @@ /** * Holds a reference to the current Ant Task for logging. Replaces the old * StaticLoggerBinder singleton pattern used with SLF4J 1.x. + *

+ * Uses ThreadLocal to ensure thread-safety when Ant runs tasks in parallel. + *

*/ public final class AntTaskHolder { - private static volatile Task task; + private static final ThreadLocal task = new ThreadLocal<>(); private AntTaskHolder() { } @@ -36,7 +39,7 @@ private AntTaskHolder() { * @param t the Ant task */ public static void setTask(Task t) { - task = t; + task.set(t); } /** @@ -45,6 +48,15 @@ public static void setTask(Task t) { * @return the Ant task, or null if not set */ public static Task getTask() { - return task; + return task.get(); + } + + /** + * Removes the current Ant task from the thread-local storage. + * This should be called when the task completes to prevent memory leaks + * in environments with thread pooling. + */ + public static void remove() { + task.remove(); } } diff --git a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java index afa1aa65599..5f4f6011af6 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java +++ b/ant/src/main/java/org/owasp/dependencycheck/taskdefs/Purge.java @@ -121,6 +121,7 @@ public final void execute() throws BuildException { executeWithContextClassloader(); } finally { Thread.currentThread().setContextClassLoader(current); + AntTaskHolder.remove(); } } From ffb3408fd8fb030da874eccedb19a93cd7c747f4 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 07:56:54 -0500 Subject: [PATCH 4/6] fix: Store and return actual logger name in AntLoggerAdapter (#8310) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jeremylong <862914+jeremylong@users.noreply.github.com> --- .../ant/logging/AntLoggerAdapter.java | 14 ++++++++++++-- .../ant/logging/AntLoggerFactory.java | 9 ++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java index 3dd195ea518..66a9afb27b7 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java +++ b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerAdapter.java @@ -17,6 +17,7 @@ */ package org.owasp.dependencycheck.ant.logging; +import java.util.Objects; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; import org.slf4j.Logger; @@ -36,11 +37,20 @@ public class AntLoggerAdapter implements Logger { /** * The logger name. */ - private static final String NAME = "dependency-check-ant"; + private final String name; + + /** + * Constructor. + * + * @param name the logger name + */ + public AntLoggerAdapter(String name) { + this.name = Objects.requireNonNull(name, "Logger name cannot be null"); + } @Override public String getName() { - return NAME; + return name; } private Task task() { diff --git a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerFactory.java b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerFactory.java index 070c85ebd7c..1c8dd84ac75 100644 --- a/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerFactory.java +++ b/ant/src/main/java/org/owasp/dependencycheck/ant/logging/AntLoggerFactory.java @@ -27,19 +27,14 @@ */ public class AntLoggerFactory implements ILoggerFactory { - /** - * A reference to the Ant logger Adapter. - */ - private final AntLoggerAdapter antLoggerAdapter = new AntLoggerAdapter(); - /** * Returns the Ant logger adapter. * - * @param name ignored in this implementation + * @param name the logger name * @return the Ant logger adapter */ @Override public Logger getLogger(String name) { - return antLoggerAdapter; + return new AntLoggerAdapter(name); } } From 691b60aad3e85cbaa39827c8e7d34757a9e73269 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sun, 22 Feb 2026 06:46:37 -0500 Subject: [PATCH 5/6] fix: add tests per peer review --- .../logging/AntSlf4jServiceProviderTest.java | 173 ++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 ant/src/test/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProviderTest.java diff --git a/ant/src/test/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProviderTest.java b/ant/src/test/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProviderTest.java new file mode 100644 index 00000000000..af95c45a748 --- /dev/null +++ b/ant/src/test/java/org/owasp/dependencycheck/ant/logging/AntSlf4jServiceProviderTest.java @@ -0,0 +1,173 @@ +/* + * This file is part of dependency-check-ant. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright (c) 2015 The OWASP Foundation. All Rights Reserved. + */ +package org.owasp.dependencycheck.ant.logging; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ServiceLoader; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.spi.SLF4JServiceProvider; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +/** + * Tests that the {@link AntSlf4jServiceProvider} is discoverable via the + * {@link ServiceLoader} mechanism and that log output is routed through the + * Ant task. + */ +class AntSlf4jServiceProviderTest { + + @AfterEach + void tearDown() { + AntTaskHolder.remove(); + } + + /** + * Verifies the META-INF/services descriptor exists in src/main/resources + * and that ServiceLoader can discover the provider when that directory is + * on the classpath (simulates the packaged JAR). + */ + @Test + void testProviderIsDiscoverableViaServiceLoader() throws Exception { + // Build a classloader that includes src/main/resources so the + // META-INF/services file is visible, as it would be in the packaged JAR. + Path resources = Paths.get("src", "main", "resources"); + try (URLClassLoader cl = new URLClassLoader( + new URL[]{resources.toUri().toURL()}, + getClass().getClassLoader())) { + + ServiceLoader loader = ServiceLoader.load(SLF4JServiceProvider.class, cl); + boolean found = false; + for (SLF4JServiceProvider provider : loader) { + if (provider instanceof AntSlf4jServiceProvider) { + found = true; + break; + } + } + assertTrue(found, + "AntSlf4jServiceProvider was not found via ServiceLoader; " + + "check META-INF/services/org.slf4j.spi.SLF4JServiceProvider"); + } + } + + /** + * Verifies the services descriptor file contents match the provider class. + */ + @Test + void testServiceDescriptorContainsCorrectClassName() throws Exception { + try (InputStream is = getClass().getClassLoader() + .getResourceAsStream("META-INF/services/org.slf4j.spi.SLF4JServiceProvider")) { + if (is == null) { + // The file may not be on the test classpath due to resource + // filtering; load it directly from source. + Path file = Paths.get("src", "main", "resources", + "META-INF", "services", "org.slf4j.spi.SLF4JServiceProvider"); + assertTrue(file.toFile().exists(), + "Service descriptor file not found at " + file); + try (BufferedReader reader = java.nio.file.Files.newBufferedReader(file)) { + String line = reader.readLine(); + assertNotNull(line); + assertEquals(AntSlf4jServiceProvider.class.getName(), line.trim()); + } + } else { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { + String line = reader.readLine(); + assertNotNull(line); + assertEquals(AntSlf4jServiceProvider.class.getName(), line.trim()); + } + } + } + } + + @Test + void testInitializeCreatesFactories() { + AntSlf4jServiceProvider provider = new AntSlf4jServiceProvider(); + provider.initialize(); + + assertNotNull(provider.getLoggerFactory(), "LoggerFactory should not be null after initialize()"); + assertInstanceOf(AntLoggerFactory.class, provider.getLoggerFactory()); + assertNotNull(provider.getMarkerFactory(), "MarkerFactory should not be null after initialize()"); + assertNotNull(provider.getMDCAdapter(), "MDCAdapter should not be null after initialize()"); + assertEquals("2.0", provider.getRequestedApiVersion()); + } + + @Test + void testLoggerFactoryReturnsAntLoggerAdapter() { + AntSlf4jServiceProvider provider = new AntSlf4jServiceProvider(); + provider.initialize(); + + Logger logger = provider.getLoggerFactory().getLogger("test.logger"); + assertInstanceOf(AntLoggerAdapter.class, logger, + "Logger should be an AntLoggerAdapter instance"); + assertEquals("test.logger", logger.getName()); + } + + @Test + void testLogOutputRoutedThroughAntTask() { + Task mockTask = mock(Task.class); + AntTaskHolder.setTask(mockTask); + + AntSlf4jServiceProvider provider = new AntSlf4jServiceProvider(); + provider.initialize(); + Logger logger = provider.getLoggerFactory().getLogger("test.routing"); + + logger.info("hello from SLF4J"); + + verify(mockTask).log("hello from SLF4J", Project.MSG_INFO); + } + + @Test + void testLogLevelMappings() { + Task mockTask = mock(Task.class); + AntTaskHolder.setTask(mockTask); + + AntSlf4jServiceProvider provider = new AntSlf4jServiceProvider(); + provider.initialize(); + Logger logger = provider.getLoggerFactory().getLogger("test.levels"); + + logger.trace("trace-msg"); + verify(mockTask).log("trace-msg", Project.MSG_VERBOSE); + + logger.debug("debug-msg"); + verify(mockTask).log("debug-msg", Project.MSG_DEBUG); + + logger.info("info-msg"); + verify(mockTask).log("info-msg", Project.MSG_INFO); + + logger.warn("warn-msg"); + verify(mockTask).log("warn-msg", Project.MSG_WARN); + + logger.error("error-msg"); + verify(mockTask).log("error-msg", Project.MSG_ERR); + } +} From a8d09440bfbfe2f60d1edd0dceb941b47cf363c2 Mon Sep 17 00:00:00 2001 From: Jeremy Long Date: Sun, 22 Feb 2026 06:56:23 -0500 Subject: [PATCH 6/6] fix: ensure services directory is pacakged --- ant/pom.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ant/pom.xml b/ant/pom.xml index 522cc407c1f..54aff7b230f 100644 --- a/ant/pom.xml +++ b/ant/pom.xml @@ -43,6 +43,13 @@ Copyright (c) 2013 - Jeremy Long. All Rights Reserved. true + + ${basedir}/src/main/resources + + META-INF/services/* + + false + ${basedir} META-INF