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

pkarwasz pushed a commit to branch fix/backport-log4j3-api
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 42cb8a4acd2653b959635de34504293fc6ff183a
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Thu Mar 14 15:58:42 2024 +0100

    Simplify `ServiceLoaderUtil`
    
    We make `ServiceLoaderUtil` more GraalVM-friendly by replacing the usage
    of `MethodHandles.Lookup` with the requirement for the caller to
    instantiate the `ServiceLoader` himself.
---
 .../logging/log4j/util/ServiceLoaderUtilTest.java  |  25 ++-
 .../logging/log4j/message/ThreadDumpMessage.java   |   8 +-
 .../logging/log4j/util/OsgiServiceLocator.java     |  55 ++++--
 .../apache/logging/log4j/util/PropertiesUtil.java  |   6 +-
 .../apache/logging/log4j/util/ProviderUtil.java    |   7 +-
 .../logging/log4j/util/ServiceLoaderUtil.java      | 193 +++++++--------------
 .../apache/logging/log4j/util/StackLocator.java    |   4 +-
 .../logging/log4j/core/appender/SmtpAppender.java  |  10 +-
 .../log4j/core/impl/ThreadContextDataInjector.java |   7 +-
 .../logging/log4j/core/util/WatchManager.java      |   5 +-
 10 files changed, 153 insertions(+), 167 deletions(-)

diff --git 
a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ServiceLoaderUtilTest.java
 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ServiceLoaderUtilTest.java
index 09b489565c..8ca74a0bee 100644
--- 
a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ServiceLoaderUtilTest.java
+++ 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/ServiceLoaderUtilTest.java
@@ -20,13 +20,15 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.ServiceConfigurationError;
+import java.util.ServiceLoader;
 import java.util.stream.Collectors;
 import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.status.StatusData;
+import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.test.BetterService;
 import org.apache.logging.log4j.test.ListStatusListener;
 import org.apache.logging.log4j.test.Service;
@@ -35,14 +37,26 @@ import org.junit.jupiter.api.Test;
 
 public class ServiceLoaderUtilTest {
 
+    private static final Logger LOGGER = StatusLogger.getLogger();
+
     @Test
     public void testServiceResolution() {
         final List<Object> services = new ArrayList<>();
-        assertDoesNotThrow(() -> 
ServiceLoaderUtil.loadServices(BetterService.class, MethodHandles.lookup(), 
false)
+        ServiceLoaderUtil.safeStream(
+                BetterService.class,
+                ServiceLoader.load(BetterService.class, 
getClass().getClassLoader()),
+                LOGGER);
+        assertDoesNotThrow(() -> ServiceLoaderUtil.safeStream(
+                        BetterService.class,
+                        ServiceLoader.load(BetterService.class, 
getClass().getClassLoader()),
+                        LOGGER)
                 .forEach(services::add));
         assertThat(services).hasSize(1);
         services.clear();
-        assertDoesNotThrow(() -> 
ServiceLoaderUtil.loadServices(PropertySource.class, MethodHandles.lookup(), 
false)
+        assertDoesNotThrow(() -> ServiceLoaderUtil.safeStream(
+                        PropertySource.class,
+                        ServiceLoader.load(PropertySource.class, 
getClass().getClassLoader()),
+                        LOGGER)
                 .forEach(services::add));
         assertThat(services).hasSize(3);
     }
@@ -51,7 +65,10 @@ public class ServiceLoaderUtilTest {
     @UsingStatusListener
     public void testBrokenServiceFile(final ListStatusListener listener) {
         final List<Service> services = new ArrayList<>();
-        assertDoesNotThrow(() -> ServiceLoaderUtil.loadServices(Service.class, 
MethodHandles.lookup(), false)
+        assertDoesNotThrow(() -> ServiceLoaderUtil.safeStream(
+                        Service.class,
+                        ServiceLoader.load(Service.class, 
getClass().getClassLoader()),
+                        LOGGER)
                 .forEach(services::add));
         assertEquals(2, services.size());
         // A warning for each broken service
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java
index 18ed7befe4..4ddbdc5c5f 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/message/ThreadDumpMessage.java
@@ -24,10 +24,11 @@ import aQute.bnd.annotation.spi.ServiceConsumer;
 import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
 import java.io.Serializable;
-import java.lang.invoke.MethodHandles;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.ServiceLoader;
 import org.apache.logging.log4j.message.ThreadDumpMessage.ThreadInfoFactory;
+import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.Lazy;
 import org.apache.logging.log4j.util.ServiceLoaderUtil;
 import org.apache.logging.log4j.util.StringBuilderFormattable;
@@ -61,7 +62,10 @@ public class ThreadDumpMessage implements Message, 
StringBuilderFormattable {
     }
 
     private static ThreadInfoFactory initFactory() {
-        return ServiceLoaderUtil.loadServices(ThreadInfoFactory.class, 
MethodHandles.lookup(), false)
+        return ServiceLoaderUtil.safeStream(
+                        ThreadInfoFactory.class,
+                        ServiceLoader.load(ThreadInfoFactory.class, 
ThreadDumpMessage.class.getClassLoader()),
+                        StatusLogger.getLogger())
                 .findFirst()
                 .orElseGet(BasicThreadInfoFactory::new);
     }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/OsgiServiceLocator.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/OsgiServiceLocator.java
index d061ccbd6d..46157290c1 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/OsgiServiceLocator.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/OsgiServiceLocator.java
@@ -24,6 +24,7 @@ import org.apache.logging.log4j.status.StatusLogger;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.wiring.BundleRevision;
 
 public class OsgiServiceLocator {
 
@@ -57,29 +58,53 @@ public class OsgiServiceLocator {
 
     public static <T> Stream<T> loadServices(final Class<T> serviceType, final 
Lookup lookup, final boolean verbose) {
         final Class<?> lookupClass = Objects.requireNonNull(lookup, 
"lookup").lookupClass();
-        final Bundle bundle = 
FrameworkUtil.getBundle(Objects.requireNonNull(lookupClass, "lookupClass"));
-        if (bundle != null) {
+        return loadServices(serviceType, lookupClass, 
StatusLogger.getLogger());
+    }
+
+    static <T> Stream<T> loadServices(final Class<T> serviceType, final 
Class<?> callerClass, final Logger logger) {
+        final Bundle bundle = FrameworkUtil.getBundle(callerClass);
+        if (bundle != null && !isFragment(bundle)) {
             final BundleContext ctx = bundle.getBundleContext();
             if (ctx == null) {
-                if (verbose) {
-                    StatusLogger.getLogger()
-                            .error(
-                                    "Unable to load OSGI services: The bundle 
has no valid BundleContext for serviceType = {}, lookup = {}, lookupClass = {}, 
bundle = {}",
-                                    serviceType,
-                                    lookup,
-                                    lookupClass,
-                                    bundle);
-                }
+                logger.warn(
+                        "Unable to load OSGi services for service {}: bundle 
{} (state {}) does not have a valid BundleContext",
+                        serviceType::getName,
+                        bundle::getSymbolicName,
+                        () -> {
+                            switch (bundle.getState()) {
+                                case Bundle.UNINSTALLED:
+                                    return "UNINSTALLED";
+                                case Bundle.INSTALLED:
+                                    return "INSTALLED";
+                                case Bundle.RESOLVED:
+                                    return "RESOLVED";
+                                case Bundle.STARTING:
+                                    return "STARTING";
+                                case Bundle.STOPPING:
+                                    return "STOPPING";
+                                case Bundle.ACTIVE:
+                                    return "ACTIVE";
+                                default:
+                                    return "UNKNOWN";
+                            }
+                        });
+
             } else {
                 try {
                     return ctx.getServiceReferences(serviceType, 
null).stream().map(ctx::getService);
-                } catch (Throwable e) {
-                    if (verbose) {
-                        StatusLogger.getLogger().error("Unable to load OSGI 
services for service {}", serviceType, e);
-                    }
+                } catch (final Exception e) {
+                    logger.error("Unable to load OSGI services for service 
{}", serviceType, e);
                 }
             }
         }
         return Stream.empty();
     }
+
+    private static boolean isFragment(final Bundle bundle) {
+        try {
+            return (bundle.adapt(BundleRevision.class).getTypes() & 
BundleRevision.TYPE_FRAGMENT) != 0;
+        } catch (final SecurityException ignored) {
+            return false;
+        }
+    }
 }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
index daf9163203..310f432edd 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertiesUtil.java
@@ -21,7 +21,6 @@ import aQute.bnd.annotation.Resolution;
 import aQute.bnd.annotation.spi.ServiceConsumer;
 import java.io.IOException;
 import java.io.InputStream;
-import java.lang.invoke.MethodHandles;
 import java.nio.charset.Charset;
 import java.time.Duration;
 import java.time.temporal.ChronoUnit;
@@ -486,7 +485,10 @@ public final class PropertiesUtil {
             }
             sources.add(propertySource);
             // We don't log anything on the status logger.
-            ServiceLoaderUtil.loadServices(PropertySource.class, 
MethodHandles.lookup(), false, false)
+            ServiceLoaderUtil.safeStream(
+                            PropertySource.class,
+                            ServiceLoader.load(PropertySource.class, 
PropertiesUtil.class.getClassLoader()),
+                            LOGGER)
                     .forEach(sources::add);
 
             reload();
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java
index a669bf7143..c02526b4a0 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ProviderUtil.java
@@ -24,13 +24,13 @@ import aQute.bnd.annotation.Resolution;
 import aQute.bnd.annotation.spi.ServiceConsumer;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import java.io.IOException;
-import java.lang.invoke.MethodHandles;
 import java.net.URL;
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Properties;
+import java.util.ServiceLoader;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.stream.Collectors;
@@ -152,7 +152,10 @@ public final class ProviderUtil {
                 STARTUP_LOCK.lockInterruptibly();
                 try {
                     if (PROVIDER == null) {
-                        ServiceLoaderUtil.loadServices(Provider.class, 
MethodHandles.lookup(), false)
+                        ServiceLoaderUtil.safeStream(
+                                        Provider.class,
+                                        ServiceLoader.load(Provider.class, 
ProviderUtil.class.getClassLoader()),
+                                        LOGGER)
                                 .filter(provider -> 
validVersion(provider.getVersions()))
                                 .forEach(ProviderUtil::addProvider);
 
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java
index cf906eab69..30b56f83b5 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/ServiceLoaderUtil.java
@@ -16,30 +16,41 @@
  */
 package org.apache.logging.log4j.util;
 
-import java.lang.invoke.CallSite;
-import java.lang.invoke.LambdaMetafactory;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles.Lookup;
-import java.lang.invoke.MethodType;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.Collections;
+import static java.util.Objects.requireNonNull;
+
+import aQute.bnd.annotation.baseline.BaselineIgnore;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
-import java.util.Set;
-import java.util.Spliterator;
+import java.util.Spliterators;
 import java.util.function.Consumer;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.status.StatusLogger;
 
 /**
- * This class should be considered internal.
+ * An utility class to retrieve services in a safe way.
+ * <p>
+ *     This class should be considered internal.
+ * </p>
+ * <p>
+ *     A common source of {@link ServiceLoader} failures, when running in a 
multi-classloader environment, is the
+ *     presence of multiple classes with the same class name in the same 
classloader hierarchy. Since {@code
+ *     ServiceLoader} retrieves services by class name, it is entirely 
possible that the registered services don't
+ *     extend the required interface and cause an exception to be thrown by 
{@code ServiceLoader}.
+ * </p>
+ * <p>
+ *     The purpose of this class is to:
+ * </p>
+ * <ol>
+ *     <li>skip faulty services, allowing for a partial retrieval of the good 
ones,</li>
+ *     <li>allow to integrate other sources of services like OSGi 
services.</li>
+ * </ol>
  */
 @InternalApi
+@BaselineIgnore("2.24.0")
 public final class ServiceLoaderUtil {
 
     private static final int MAX_BROKEN_SERVICES = 8;
@@ -47,110 +58,43 @@ public final class ServiceLoaderUtil {
     private ServiceLoaderUtil() {}
 
     /**
-     * Retrieves the available services from the caller's classloader.
-     *
-     * Broken services will be ignored.
-     *
-     * @param <T>         The service type.
-     * @param serviceType The class of the service.
-     * @param lookup      The calling class data.
-     * @return A stream of service instances.
-     */
-    public static <T> Stream<T> loadServices(final Class<T> serviceType, final 
Lookup lookup) {
-        return loadServices(serviceType, lookup, false);
-    }
-
-    /**
-     * Retrieves the available services from the caller's classloader and 
possibly
-     * the thread context classloader.
-     *
-     * Broken services will be ignored.
-     *
-     * @param <T>         The service type.
-     * @param serviceType The class of the service.
-     * @param lookup      The calling class data.
-     * @param useTccl     If true the thread context classloader will also be 
used.
-     * @return A stream of service instances.
+     * Retrieves services registered with {@link ServiceLoader}
+     * <p>
+     *     It ignores the most common service loading errors.
+     * </p>
+     * @param serviceType The service type to use for OSGi service retrieval.
+     * @param serviceLoader The service loader instance to use.
+     * @param logger The logger to use to report service failures.
+     * @return A stream of all correctly loaded services.
+     * @since 2.24.0
      */
-    public static <T> Stream<T> loadServices(final Class<T> serviceType, final 
Lookup lookup, final boolean useTccl) {
-        return loadServices(serviceType, lookup, useTccl, true);
-    }
-
-    static <T> Stream<T> loadServices(
-            final Class<T> serviceType, final Lookup lookup, final boolean 
useTccl, final boolean verbose) {
-        final ClassLoader classLoader = lookup.lookupClass().getClassLoader();
-        Stream<T> services = loadClassloaderServices(serviceType, lookup, 
classLoader, verbose);
-        if (useTccl) {
-            final ClassLoader contextClassLoader = 
LoaderUtil.getThreadContextClassLoader();
-            if (contextClassLoader != classLoader) {
-                services = Stream.concat(
-                        services, loadClassloaderServices(serviceType, lookup, 
contextClassLoader, verbose));
-            }
-        }
-        if (OsgiServiceLocator.isAvailable()) {
-            services = Stream.concat(services, 
OsgiServiceLocator.loadServices(serviceType, lookup, verbose));
-        }
-        final Set<Class<?>> classes = new HashSet<>();
-        // only the first occurrence of a class
-        return services.filter(service -> classes.add(service.getClass()));
-    }
-
-    static <T> Stream<T> loadClassloaderServices(
-            final Class<T> serviceType, final Lookup lookup, final ClassLoader 
classLoader, final boolean verbose) {
-        return StreamSupport.stream(new 
ServiceLoaderSpliterator<T>(serviceType, lookup, classLoader, verbose), false);
+    public static <S> Stream<S> safeStream(
+            final Class<S> serviceType, final ServiceLoader<? extends S> 
serviceLoader, final Logger logger) {
+        requireNonNull(serviceLoader, "serviceLoader");
+        final Collection<Class<?>> classes = new HashSet<>();
+        final Stream<S> services =
+                StreamSupport.stream(new 
ServiceLoaderSpliterator<>(serviceType, serviceLoader, logger), false);
+        // Caller class may be null
+        final Class<?> callerClass = StackLocatorUtil.getCallerClass(2);
+        final Stream<S> allServices = OsgiServiceLocator.isAvailable() && 
callerClass != null
+                ? Stream.concat(services, 
OsgiServiceLocator.loadServices(serviceType, callerClass, logger))
+                : services;
+        return allServices
+                // only the first occurrence of a class
+                .filter(service -> classes.add(service.getClass()));
     }
 
-    static <T> Iterable<T> callServiceLoader(
-            final Lookup lookup, final Class<T> serviceType, final ClassLoader 
classLoader, final boolean verbose) {
-        try {
-            // Creates a lambda in the caller's domain that calls 
`ServiceLoader`
-            final MethodHandle loadHandle = lookup.findStatic(
-                    ServiceLoader.class,
-                    "load",
-                    MethodType.methodType(ServiceLoader.class, Class.class, 
ClassLoader.class));
-            final CallSite callSite = LambdaMetafactory.metafactory(
-                    lookup,
-                    "run",
-                    MethodType.methodType(PrivilegedAction.class, Class.class, 
ClassLoader.class),
-                    MethodType.methodType(Object.class),
-                    loadHandle,
-                    MethodType.methodType(ServiceLoader.class));
-            final PrivilegedAction<ServiceLoader<T>> action = 
(PrivilegedAction<ServiceLoader<T>>)
-                    callSite.getTarget() //
-                            .bindTo(serviceType)
-                            .bindTo(classLoader)
-                            .invoke();
-            final ServiceLoader<T> serviceLoader;
-            if (System.getSecurityManager() == null) {
-                serviceLoader = action.run();
-            } else {
-                final MethodHandle privilegedHandle = lookup.findStatic(
-                        AccessController.class,
-                        "doPrivileged",
-                        MethodType.methodType(Object.class, 
PrivilegedAction.class));
-                serviceLoader = (ServiceLoader<T>) 
privilegedHandle.invoke(action);
-            }
-            return serviceLoader;
-        } catch (Throwable e) {
-            if (verbose) {
-                StatusLogger.getLogger().error("Unable to load services for 
service {}", serviceType, e);
-            }
-        }
-        return Collections.emptyList();
-    }
-
-    private static class ServiceLoaderSpliterator<S> implements Spliterator<S> 
{
-
-        private final Iterator<S> serviceIterator;
-        private final Logger logger;
+    private static final class ServiceLoaderSpliterator<S> extends 
Spliterators.AbstractSpliterator<S> {
         private final String serviceName;
+        private final Iterator<? extends S> serviceIterator;
+        private final Logger logger;
 
-        public ServiceLoaderSpliterator(
-                final Class<S> serviceType, final Lookup lookup, final 
ClassLoader classLoader, final boolean verbose) {
-            this.serviceIterator =
-                    callServiceLoader(lookup, serviceType, classLoader, 
verbose).iterator();
-            this.logger = verbose ? StatusLogger.getLogger() : null;
-            this.serviceName = serviceType.toString();
+        private ServiceLoaderSpliterator(
+                final Class<S> serviceType, final Iterable<? extends S> 
serviceLoader, final Logger logger) {
+            super(Long.MAX_VALUE, ORDERED | NONNULL | IMMUTABLE);
+            this.serviceName = serviceType.getName();
+            this.serviceIterator = serviceLoader.iterator();
+            this.logger = logger;
         }
 
         @Override
@@ -162,33 +106,14 @@ public final class ServiceLoaderUtil {
                         action.accept(serviceIterator.next());
                         return true;
                     }
-                } catch (ServiceConfigurationError | LinkageError e) {
-                    if (logger != null) {
-                        logger.warn("Unable to load service class for service 
{}", serviceName, e);
-                    }
-                } catch (Throwable e) {
-                    if (logger != null) {
-                        logger.warn("Unable to load service class for service 
{}", serviceName, e);
-                    }
+                } catch (final ServiceConfigurationError | LinkageError e) {
+                    logger.warn("Unable to load implementation for service 
{}", serviceName, e);
+                } catch (final Exception e) {
+                    logger.warn("Unexpected exception  while loading 
implementation for service {}", serviceName, e);
                     throw e;
                 }
             }
             return false;
         }
-
-        @Override
-        public Spliterator<S> trySplit() {
-            return null;
-        }
-
-        @Override
-        public long estimateSize() {
-            return Long.MAX_VALUE;
-        }
-
-        @Override
-        public int characteristics() {
-            return NONNULL | IMMUTABLE;
-        }
     }
 }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocator.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocator.java
index bc20af0daf..27982ad4d9 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocator.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocator.java
@@ -69,7 +69,9 @@ public final class StackLocator {
         Method getCallerClassMethod;
         int java7u25CompensationOffset = 0;
         try {
-            final Class<?> sunReflectionClass = 
LoaderUtil.loadClass("sun.reflect.Reflection");
+            // Do not use `LoaderUtil` here, since it causes a cycle of 
dependencies:
+            // LoaderUtil -> PropertiesUtil -> ServiceLoaderUtil -> 
StackLocator
+            final Class<?> sunReflectionClass = 
Class.forName("sun.reflect.Reflection");
             getCallerClassMethod = 
sunReflectionClass.getDeclaredMethod("getCallerClass", int.class);
             Object o = getCallerClassMethod.invoke(null, 0);
             getCallerClassMethod.invoke(null, 0);
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java
index c1299311ea..b610603b4b 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/SmtpAppender.java
@@ -17,7 +17,7 @@
 package org.apache.logging.log4j.core.appender;
 
 import java.io.Serializable;
-import java.lang.invoke.MethodHandles;
+import java.util.ServiceLoader;
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.Core;
 import org.apache.logging.log4j.core.Filter;
@@ -45,6 +45,7 @@ import org.apache.logging.log4j.core.net.SmtpManager;
 import org.apache.logging.log4j.core.net.ssl.SslConfiguration;
 import org.apache.logging.log4j.core.util.Booleans;
 import org.apache.logging.log4j.core.util.Integers;
+import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.ServiceLoaderUtil;
 import org.apache.logging.log4j.util.Strings;
 
@@ -300,8 +301,11 @@ public final class SmtpAppender extends AbstractAppender {
                     bufferSize,
                     sslConfiguration,
                     getFilter().toString());
-            final MailManagerFactory factory = ServiceLoaderUtil.loadServices(
-                            MailManagerFactory.class, MethodHandles.lookup())
+            final MailManagerFactory factory = ServiceLoaderUtil.safeStream(
+                            MailManagerFactory.class,
+                            ServiceLoader.load(
+                                    MailManagerFactory.class, 
getClass().getClassLoader()),
+                            StatusLogger.getLogger())
                     .findAny()
                     .orElseGet(() -> SmtpManager.FACTORY);
             final MailManager smtpManager = 
AbstractManager.getManager(data.getManagerName(), factory, data);
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
index 24f34936e6..332b877a51 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
@@ -19,13 +19,13 @@ package org.apache.logging.log4j.core.impl;
 import aQute.bnd.annotation.Cardinality;
 import aQute.bnd.annotation.Resolution;
 import aQute.bnd.annotation.spi.ServiceConsumer;
-import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.ServiceLoader;
 import java.util.concurrent.ConcurrentLinkedDeque;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.ThreadContext;
@@ -79,7 +79,10 @@ public class ThreadContextDataInjector {
 
     private static List<ContextDataProvider> getServiceProviders() {
         final List<ContextDataProvider> providers = new ArrayList<>();
-        ServiceLoaderUtil.loadServices(ContextDataProvider.class, 
MethodHandles.lookup(), false)
+        ServiceLoaderUtil.safeStream(
+                        ContextDataProvider.class,
+                        ServiceLoader.load(ContextDataProvider.class, 
ThreadContextDataInjector.class.getClassLoader()),
+                        LOGGER)
                 .forEach(providers::add);
         return Collections.unmodifiableList(providers);
     }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
index 491c212f6f..1761498087 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/WatchManager.java
@@ -20,12 +20,12 @@ import aQute.bnd.annotation.Cardinality;
 import aQute.bnd.annotation.Resolution;
 import aQute.bnd.annotation.spi.ServiceConsumer;
 import java.io.File;
-import java.lang.invoke.MethodHandles;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.ServiceLoader;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
@@ -143,7 +143,8 @@ public class WatchManager extends AbstractLifeCycle {
 
     public WatchManager(final ConfigurationScheduler scheduler) {
         this.scheduler = Objects.requireNonNull(scheduler, "scheduler");
-        eventServiceList = 
ServiceLoaderUtil.loadServices(WatchEventService.class, MethodHandles.lookup(), 
true)
+        eventServiceList = ServiceLoaderUtil.safeStream(
+                        WatchEventService.class, 
ServiceLoader.load(WatchEventService.class), logger)
                 .collect(Collectors.toList());
     }
 

Reply via email to