You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2024/03/19 12:48:13 UTC
(logging-log4j2) 01/06: Simplify `ServiceLoaderUtil`
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 <pi...@karwasz.org>
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());
}