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

mattsicker pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 589dcdaabf21a6da07d8979cc25ded5ed975d8b4
Author: Matt Sicker <[email protected]>
AuthorDate: Sun Oct 1 17:38:44 2023 -0500

    Clean up and better document LoaderUtil
    
    This makes a few updates here. First, javadoc comments have been updated to 
properly document all the potential exceptions they throw. Next, unchecked 
exception variants of methods here have been created. Furthermore, use of 
SecurityManager has been overhauled to be more consistent. Finally, some unused 
functionality was removed.
    
    Signed-off-by: Matt Sicker <[email protected]>
---
 .../log4j/config/PropertiesConfiguration.java      |   2 +-
 .../apache/logging/log4j/util/LoaderUtilTest.java  |   4 +-
 .../apache/logging/log4j/spi/LoggingSystem.java    |   2 +-
 .../org/apache/logging/log4j/util/LoaderUtil.java  | 425 +++++++++++++--------
 .../apache/logging/log4j/util/PropertiesUtil.java  |  14 +-
 .../log4j/util/PropertyFilePropertySource.java     |  14 +-
 6 files changed, 282 insertions(+), 179 deletions(-)

diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
 
b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
index eee359c47e..95ed6f578e 100644
--- 
a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
+++ 
b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
@@ -592,7 +592,7 @@ public class PropertiesConfiguration extends 
Log4j1Configuration {
     private static <T> T newInstanceOf(final String className, final String 
type) {
         try {
             return LoaderUtil.newInstanceOf(className);
-        } catch (ReflectiveOperationException ex) {
+        } catch (ReflectiveOperationException | LinkageError | 
RuntimeException ex) {
             LOGGER.error("Unable to create {} {} due to {}:{}", type, 
className, ex.getClass().getSimpleName(), ex.getMessage(), ex);
             return null;
         }
diff --git 
a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilTest.java
 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilTest.java
index 59db7bf47e..5ae0bc64ae 100644
--- 
a/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilTest.java
+++ 
b/log4j-api-test/src/test/java/org/apache/logging/log4j/util/LoaderUtilTest.java
@@ -49,10 +49,10 @@ public class LoaderUtilTest {
         };
         thread.setContextClassLoader(loader);
         try {
-            assertEquals(0, 
LoaderUtil.findUrlResources("Log4j-charsets.properties", false).size());
+            assertEquals(0, 
LoaderUtil.findUrlResources("Log4j-charsets.properties").size());
 
             LoaderUtil.forceTcclOnly = false;
-            assertEquals(1, 
LoaderUtil.findUrlResources("Log4j-charsets.properties", false).size());
+            assertEquals(1, 
LoaderUtil.findUrlResources("Log4j-charsets.properties").size());
         } finally {
             thread.setContextClassLoader(tccl);
         }
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java
index a85dfd514c..b6e3a93922 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/LoggingSystem.java
@@ -221,7 +221,7 @@ public class LoggingSystem {
     }
 
     private static List<Provider> loadLegacyProviders() {
-        return LoaderUtil.findUrlResources(PROVIDER_RESOURCE, false)
+        return LoaderUtil.findUrlResources(PROVIDER_RESOURCE)
                 .stream()
                 .map(urlResource -> loadLegacyProvider(urlResource.getUrl(), 
urlResource.getClassLoader()))
                 .filter(Objects::nonNull)
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java
index 37c4de0784..7a405fdafc 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/LoaderUtil.java
@@ -17,6 +17,7 @@
 package org.apache.logging.log4j.util;
 
 import java.io.IOException;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 import java.security.AccessController;
@@ -41,26 +42,37 @@ public final class LoaderUtil {
 
     private static final ClassLoader[] EMPTY_CLASS_LOADER_ARRAY = {};
 
-    private static final SecurityManager SECURITY_MANAGER = 
System.getSecurityManager();
-
     // this variable must be lazily loaded; otherwise, we get a nice circular 
class loading problem where LoaderUtil
     // wants to use PropertiesUtil, but then PropertiesUtil wants to use 
LoaderUtil.
     private static Boolean ignoreTCCL;
 
+    private static final RuntimePermission GET_CLASS_LOADER = new 
RuntimePermission("getClassLoader");
     private static final boolean GET_CLASS_LOADER_DISABLED;
 
-    protected static Boolean forceTcclOnly;
+    static Boolean forceTcclOnly;
 
     private static final PrivilegedAction<ClassLoader> TCCL_GETTER = new 
ThreadContextClassLoaderGetter();
+    private static final PrivilegedAction<ClassLoader[]> 
CLASSLOADER_ACCUMULATOR = new ClassLoaderAccumulator();
 
     static {
-        if (SECURITY_MANAGER != null) {
+        if (System.getSecurityManager() != null) {
             boolean getClassLoaderDisabled;
             try {
-                SECURITY_MANAGER.checkPermission(new 
RuntimePermission("getClassLoader"));
+                AccessController.checkPermission(GET_CLASS_LOADER);
+                // seems like we'll be ok
                 getClassLoaderDisabled = false;
             } catch (final SecurityException ignored) {
-                getClassLoaderDisabled = true;
+                try {
+                    // let's see if we can obtain that permission
+                    AccessController.doPrivileged((PrivilegedAction<Void>) () 
-> {
+                        AccessController.checkPermission(GET_CLASS_LOADER);
+                        return null;
+                    }, null, GET_CLASS_LOADER);
+                    getClassLoaderDisabled = false;
+                } catch (final SecurityException ignore) {
+                    // no chance
+                    getClassLoaderDisabled = true;
+                }
             }
             GET_CLASS_LOADER_DISABLED = getClassLoaderDisabled;
         } else {
@@ -73,6 +85,7 @@ public final class LoaderUtil {
 
     /**
      * Returns the ClassLoader to use.
+     *
      * @return the ClassLoader.
      */
     public static ClassLoader getClassLoader() {
@@ -81,31 +94,18 @@ public final class LoaderUtil {
 
     // TODO: this method could use some explanation
     public static ClassLoader getClassLoader(final Class<?> class1, final 
Class<?> class2) {
-        final ClassLoader threadContextClassLoader = 
getThreadContextClassLoader();
-        final ClassLoader loader1 = class1 == null ? null : 
class1.getClassLoader();
-        final ClassLoader loader2 = class2 == null ? null : 
class2.getClassLoader();
-
-        if (isChild(threadContextClassLoader, loader1)) {
-            return isChild(threadContextClassLoader, loader2) ? 
threadContextClassLoader : loader2;
-        }
-        return isChild(loader1, loader2) ? loader1 : loader2;
-    }
-
-    /**
-     * Gets the current Thread ClassLoader. Returns the system ClassLoader if 
the TCCL is {@code null}. If the system
-     * ClassLoader is {@code null} as well, then the ClassLoader for this 
class is returned. If running with a
-     * {@link SecurityManager} that does not allow access to the Thread 
ClassLoader or system ClassLoader, then the
-     * ClassLoader for this class is returned.
-     *
-     * @return the current ThreadContextClassLoader.
-     */
-    public static ClassLoader getThreadContextClassLoader() {
-        if (GET_CLASS_LOADER_DISABLED) {
-            // we can at least get this class's ClassLoader regardless of 
security context
-            // however, if this is null, there's really no option left at this 
point
-            return LoaderUtil.class.getClassLoader();
-        }
-        return SECURITY_MANAGER == null ? TCCL_GETTER.run() : 
AccessController.doPrivileged(TCCL_GETTER);
+        PrivilegedAction<ClassLoader> action = () -> {
+            final ClassLoader loader1 = class1 == null ? null : 
class1.getClassLoader();
+            final ClassLoader loader2 = class2 == null ? null : 
class2.getClassLoader();
+            final ClassLoader referenceLoader = GET_CLASS_LOADER_DISABLED
+                    ? getThisClassLoader()
+                    : Thread.currentThread().getContextClassLoader();
+            if (isChild(referenceLoader, loader1)) {
+                return isChild(referenceLoader, loader2) ? referenceLoader : 
loader2;
+            }
+            return isChild(loader1, loader2) ? loader1 : loader2;
+        };
+        return AccessController.doPrivileged(action, null, GET_CLASS_LOADER);
     }
 
     /**
@@ -129,66 +129,101 @@ public final class LoaderUtil {
     }
 
     /**
+     * Looks up the ClassLoader for this current thread. If this class does 
not have the runtime permission
+     * {@code getClassLoader}, then the only ClassLoader this attempts to look 
up is the loader behind this
+     * class. When a SecurityManager is installed, this attempts to make a 
privileged call to get the current
+     * {@linkplain Thread#getContextClassLoader() thread context ClassLoader}, 
falling back to either the
+     * ClassLoader of this class or the {@linkplain 
ClassLoader#getSystemClassLoader() system ClassLoader}.
+     * When no SecurityManager is present, the same lookups are performed 
without use of {@link AccessController}.
+     * If none of these strategies can obtain a ClassLoader, then this returns 
{@code null}.
      *
+     * @return the current thread's ClassLoader, a fallback loader, or null if 
no fallback can be determined
      */
+    public static ClassLoader getThreadContextClassLoader() {
+        if (GET_CLASS_LOADER_DISABLED) {
+            // we can at least get this class's ClassLoader regardless of 
security context
+            // however, if this is null, there's really no option left at this 
point
+            try {
+                return getThisClassLoader();
+            } catch (final SecurityException ignored) {
+                return null;
+            }
+        }
+        return AccessController.doPrivileged(TCCL_GETTER, null, 
GET_CLASS_LOADER);
+    }
+
+    public static ClassLoader[] getClassLoaders() {
+        return AccessController.doPrivileged(CLASSLOADER_ACCUMULATOR, null, 
GET_CLASS_LOADER);
+    }
+
+    private static ClassLoader getThisClassLoader() {
+        return LoaderUtil.class.getClassLoader();
+    }
+
     private static class ThreadContextClassLoaderGetter implements 
PrivilegedAction<ClassLoader> {
         @Override
         public ClassLoader run() {
-            final ClassLoader cl = 
Thread.currentThread().getContextClassLoader();
-            if (cl != null) {
-                return cl;
+            final ClassLoader contextClassLoader = 
Thread.currentThread().getContextClassLoader();
+            if (contextClassLoader != null) {
+                return contextClassLoader;
+            }
+            final ClassLoader thisClassLoader = getThisClassLoader();
+            if (thisClassLoader != null || GET_CLASS_LOADER_DISABLED) {
+                return thisClassLoader;
             }
-            final ClassLoader ccl = LoaderUtil.class.getClassLoader();
-            return ccl == null && !GET_CLASS_LOADER_DISABLED ? 
ClassLoader.getSystemClassLoader() : ccl;
+            return ClassLoader.getSystemClassLoader();
         }
     }
 
-    public static ClassLoader[] getClassLoaders() {
-        final Collection<ClassLoader> classLoaders = new LinkedHashSet<>();
-        final ClassLoader tcl = getThreadContextClassLoader();
-        if (tcl != null) {
-            classLoaders.add(tcl);
-        }
-        final ModuleLayer layer = LoaderUtil.class.getModule().getLayer();
-        if (layer == null) {
-            if (!isForceTccl()) {
-                accumulateClassLoaders(LoaderUtil.class.getClassLoader(), 
classLoaders);
-                accumulateClassLoaders(tcl == null ? null : tcl.getParent(), 
classLoaders);
-                final ClassLoader systemClassLoader = 
ClassLoader.getSystemClassLoader();
-                if (systemClassLoader != null) {
-                    classLoaders.add(systemClassLoader);
-                }
+    private static class ClassLoaderAccumulator implements 
PrivilegedAction<ClassLoader[]> {
+        @Override
+        public ClassLoader[] run() {
+            final Collection<ClassLoader> classLoaders = new LinkedHashSet<>();
+            final ClassLoader tcl = TCCL_GETTER.run();
+            if (tcl != null) {
+                classLoaders.add(tcl);
             }
-        } else {
-            accumulateLayerClassLoaders(layer, classLoaders);
-            if (layer != ModuleLayer.boot()) {
-                for (final Module module : ModuleLayer.boot().modules()) {
-                    accumulateClassLoaders(module.getClassLoader(), 
classLoaders);
+            final ModuleLayer layer = LoaderUtil.class.getModule().getLayer();
+            if (layer == null) {
+                if (!isForceTccl()) {
+                    accumulateClassLoaders(getThisClassLoader(), classLoaders);
+                    accumulateClassLoaders(tcl == null ? null : 
tcl.getParent(), classLoaders);
+                    final ClassLoader systemClassLoader = 
ClassLoader.getSystemClassLoader();
+                    if (systemClassLoader != null) {
+                        classLoaders.add(systemClassLoader);
+                    }
+                }
+            } else {
+                accumulateLayerClassLoaders(layer, classLoaders);
+                if (layer != ModuleLayer.boot()) {
+                    for (final Module module : ModuleLayer.boot().modules()) {
+                        accumulateClassLoaders(module.getClassLoader(), 
classLoaders);
+                    }
                 }
             }
+            return classLoaders.toArray(EMPTY_CLASS_LOADER_ARRAY);
         }
-        return classLoaders.toArray(EMPTY_CLASS_LOADER_ARRAY);
-    }
 
-    private static void accumulateLayerClassLoaders(final ModuleLayer layer, 
final Collection<ClassLoader> classLoaders) {
-        for (final Module module : layer.modules()) {
-            accumulateClassLoaders(module.getClassLoader(), classLoaders);
-        }
-        if (layer.parents().size() > 0) {
-            for (final ModuleLayer parent : layer.parents()) {
-                accumulateLayerClassLoaders(parent, classLoaders);
+        private static void accumulateLayerClassLoaders(final ModuleLayer 
layer, final Collection<ClassLoader> classLoaders) {
+            for (final Module module : layer.modules()) {
+                accumulateClassLoaders(module.getClassLoader(), classLoaders);
+            }
+            if (!layer.parents().isEmpty()) {
+                for (final ModuleLayer parent : layer.parents()) {
+                    accumulateLayerClassLoaders(parent, classLoaders);
+                }
             }
         }
-    }
 
-    /**
-     * Adds the provided loader to the loaders collection, and traverses up 
the tree until either a null
-     * value or a classloader which has already been added is encountered.
-     */
-    private static void accumulateClassLoaders(final ClassLoader loader, final 
Collection<ClassLoader> loaders) {
-        // Some implementations may use null to represent the bootstrap class 
loader.
-        if (loader != null && loaders.add(loader)) {
-            accumulateClassLoaders(loader.getParent(), loaders);
+        /**
+         * Adds the provided loader to the loaders collection, and traverses 
up the tree until either a null
+         * value or a classloader which has already been added is encountered.
+         */
+        private static void accumulateClassLoaders(final ClassLoader loader, 
final Collection<ClassLoader> loaders) {
+            // Some implementations may use null to represent the bootstrap 
class loader.
+            if (loader != null && loaders.add(loader)) {
+                accumulateClassLoaders(loader.getParent(), loaders);
+            }
         }
     }
 
@@ -201,8 +236,8 @@ public final class LoaderUtil {
      */
     public static boolean isClassAvailable(final String className) {
         try {
-            final Class<?> clazz = loadClass(className);
-            return clazz != null;
+            loadClass(className);
+            return true;
         } catch (final ClassNotFoundException | LinkageError e) {
             return false;
         } catch (final Throwable e) {
@@ -212,110 +247,192 @@ public final class LoaderUtil {
     }
 
     /**
-     * Loads a class by name. This method respects the {@value 
LoggingSystemProperty#LOADER_IGNORE_THREAD_CONTEXT_LOADER}
-     * Log4j property. If this property is specified and set to anything 
besides {@code false}, then this class's
-     * ClassLoader will be used as specified by {@link Class#forName(String)}.
+     * Loads and initializes a class given its fully qualified class name. 
This method respects the
+     * {@link LoggingSystemProperty#LOADER_IGNORE_THREAD_CONTEXT_LOADER} Log4j 
property. If this property is specified
+     * and set to anything besides {@code false}, then this class's 
ClassLoader will be used.
      *
-     * @param className The class name.
-     * @return the Class for the given name.
-     * @throws ClassNotFoundException if the specified class name could not be 
found
+     * @param className fully qualified class name to load
+     * @return the loaded class
+     * @throws ClassNotFoundException      if the specified class name could 
not be found
+     * @throws ExceptionInInitializerError if an exception is thrown during 
class initialization
+     * @throws LinkageError                if the linkage of the class fails 
for any other reason
      * @since 2.1
      */
     public static Class<?> loadClass(final String className) throws 
ClassNotFoundException {
-        if (isIgnoreTccl()) {
-            return Class.forName(className);
+        ClassLoader classLoader = isIgnoreTccl() ? getThisClassLoader() : 
getThreadContextClassLoader();
+        if (classLoader == null) {
+            classLoader = getThisClassLoader();
         }
+        return Class.forName(className, true, classLoader);
+    }
+
+    /**
+     * Loads and initializes a class given its fully qualified class name. All 
checked reflective operation
+     * exceptions are translated into equivalent {@link LinkageError} classes.
+     *
+     * @param className fully qualified class name to load
+     * @return the loaded class
+     * @throws NoClassDefFoundError        if the specified class name could 
not be found
+     * @throws ExceptionInInitializerError if an exception is thrown during 
class initialization
+     * @throws LinkageError                if the linkage of the class fails 
for any other reason
+     * @see #loadClass(String)
+     * @since 3.0.0
+     */
+    public static Class<?> loadClassUnchecked(final String className) {
         try {
-            final ClassLoader tccl = getThreadContextClassLoader();
-            if (tccl != null) {
-                return tccl.loadClass(className);
-            }
-        } catch (final Throwable ignored) {
+            return loadClass(className);
+        } catch (final ClassNotFoundException e) {
+            final NoClassDefFoundError error = new 
NoClassDefFoundError(e.getMessage());
+            error.initCause(e);
+            throw error;
         }
-        return Class.forName(className);
     }
 
     /**
      * Loads and instantiates a Class using the default constructor.
      *
-     * @param <T> the type of the class modeled by the {@code Class} object.
+     * @param <T>   the type of the class modeled by the {@code Class} object.
      * @param clazz The class.
      * @return new instance of the class.
-     * @throws IllegalAccessException if the class can't be instantiated 
through a public constructor
-     * @throws InstantiationException if there was an exception whilst 
instantiating the class
-     * @throws InvocationTargetException if there was an exception whilst 
constructing the class
+     * @throws NoSuchMethodException       if no zero-arg constructor exists
+     * @throws SecurityException           if this class is not allowed to 
access declared members of the provided class
+     * @throws IllegalAccessException      if the class can't be instantiated 
through a public constructor
+     * @throws InstantiationException      if the provided class is abstract 
or an interface
+     * @throws InvocationTargetException   if an exception is thrown by the 
constructor
+     * @throws ExceptionInInitializerError if an exception was thrown while 
initializing the class
      * @since 2.7
      */
     public static <T> T newInstanceOf(final Class<T> clazz)
-            throws InstantiationException, IllegalAccessException, 
InvocationTargetException {
+            throws InstantiationException, IllegalAccessException, 
InvocationTargetException, NoSuchMethodException {
+        final Constructor<T> constructor = clazz.getDeclaredConstructor();
+        return constructor.newInstance();
+    }
+
+    /**
+     * Creates an instance of the provided class using the default 
constructor. All checked reflective operation
+     * exceptions are translated into {@link LinkageError} or {@link 
InternalException}.
+     *
+     * @param clazz class to instantiate
+     * @param <T>   the type of the object being instantiated
+     * @return instance of the class
+     * @throws NoSuchMethodError  if no zero-arg constructor exists
+     * @throws SecurityException  if this class is not allowed to access 
declared members of the provided class
+     * @throws InternalException  if an exception is thrown by the constructor
+     * @throws InstantiationError if the provided class is abstract or an 
interface
+     * @throws IllegalAccessError if the class cannot be accessed
+     * @since 3.0.0
+     */
+    public static <T> T newInstanceOfUnchecked(final Class<T> clazz) {
         try {
-            return clazz.getConstructor().newInstance();
-        } catch (final NoSuchMethodException ignored) {
-            // FIXME: looking at the code for Class.newInstance(), this seems 
to do the same thing as above
-            return clazz.newInstance();
+            return newInstanceOf(clazz);
+        } catch (final NoSuchMethodException e) {
+            final NoSuchMethodError error = new 
NoSuchMethodError(e.getMessage());
+            error.initCause(e);
+            throw error;
+        } catch (final InvocationTargetException e) {
+            final Throwable cause = e.getCause();
+            throw new InternalException(cause);
+        } catch (final InstantiationException e) {
+            final InstantiationError error = new 
InstantiationError(e.getMessage());
+            error.initCause(e);
+            throw error;
+        } catch (final IllegalAccessException e) {
+            final IllegalAccessError error = new 
IllegalAccessError(e.getMessage());
+            error.initCause(e);
+            throw error;
         }
     }
 
     /**
      * Loads and instantiates a Class using the default constructor.
      *
-     * @param className The class name.
-     * @param <T> The class's type.
-     * @return new instance of the class.
-     * @throws ClassNotFoundException if the class isn't available to the 
usual ClassLoaders
-     * @throws IllegalAccessException if the class can't be instantiated 
through a public constructor
-     * @throws InstantiationException if there was an exception whilst 
instantiating the class
-     * @throws InvocationTargetException if there was an exception whilst 
constructing the class
+     * @param className fully qualified class name to load, initialize, and 
construct
+     * @param <T>       type the class must be compatible with
+     * @return new instance of the class
+     * @throws ClassNotFoundException      if the class isn't available to the 
usual ClassLoaders
+     * @throws ExceptionInInitializerError if an exception was thrown while 
initializing the class
+     * @throws LinkageError                if the linkage of the class fails 
for any other reason
+     * @throws ClassCastException          if the class is not compatible with 
the generic type parameter provided
+     * @throws NoSuchMethodException       if no zero-arg constructor exists
+     * @throws SecurityException           if this class is not allowed to 
access declared members of the provided class
+     * @throws IllegalAccessException      if the class can't be instantiated 
through a public constructor
+     * @throws InstantiationException      if the provided class is abstract 
or an interface
+     * @throws InvocationTargetException   if an exception is thrown by the 
constructor
      * @since 2.1
      */
-    @SuppressWarnings("unchecked")
     public static <T> T newInstanceOf(final String className) throws 
ClassNotFoundException, IllegalAccessException,
-            InstantiationException, InvocationTargetException {
-        return newInstanceOf((Class<T>) loadClass(className));
+            InstantiationException, InvocationTargetException, 
NoSuchMethodException {
+        final Class<T> clazz = Cast.cast(loadClass(className));
+        return newInstanceOf(clazz);
+    }
+
+    /**
+     * Loads and instantiates a class by name using its default constructor. 
All checked reflective operation
+     * exceptions are translated into corresponding {@link LinkageError} 
classes.
+     *
+     * @param className fully qualified class name to load, initialize, and 
construct
+     * @param <T>       type the class must be compatible with
+     * @return new instance of the class
+     * @throws NoClassDefFoundError        if the specified class name could 
not be found
+     * @throws ExceptionInInitializerError if an exception is thrown during 
class initialization
+     * @throws ClassCastException          if the class is not compatible with 
the generic type parameter provided
+     * @throws NoSuchMethodError           if no zero-arg constructor exists
+     * @throws SecurityException           if this class is not allowed to 
access declared members of the provided class
+     * @throws InternalException           if an exception is thrown by the 
constructor
+     * @throws InstantiationError          if the provided class is abstract 
or an interface
+     * @throws IllegalAccessError          if the class cannot be accessed
+     * @throws LinkageError                if the linkage of the class fails 
for any other reason
+     */
+    public static <T> T newInstanceOfUnchecked(final String className) {
+        final Class<T> clazz = Cast.cast(loadClassUnchecked(className));
+        return newInstanceOfUnchecked(clazz);
     }
 
     /**
      * Loads and instantiates a derived class using its default constructor.
      *
      * @param className The class name.
-     * @param clazz The class to cast it to.
-     * @param <T> The type of the class to check.
+     * @param clazz     The class to cast it to.
+     * @param <T>       The type of the class to check.
      * @return new instance of the class cast to {@code T}
-     * @throws ClassNotFoundException if the class isn't available to the 
usual ClassLoaders
-     * @throws IllegalAccessException if the class can't be instantiated 
through a public constructor
-     * @throws InstantiationException if there was an exception whilst 
instantiating the class
-     * @throws InvocationTargetException if there was an exception whilst 
constructing the class
-     * @throws ClassCastException if the constructed object isn't type 
compatible with {@code T}
+     * @throws ClassNotFoundException      if the class isn't available to the 
usual ClassLoaders
+     * @throws ExceptionInInitializerError if an exception is thrown during 
class initialization
+     * @throws LinkageError                if the linkage of the class fails 
for any other reason
+     * @throws ClassCastException          if the constructed object isn't 
type compatible with {@code T}
+     * @throws NoSuchMethodException       if no zero-arg constructor exists
+     * @throws SecurityException           if this class is not allowed to 
access declared members of the provided class
+     * @throws IllegalAccessException      if the class can't be instantiated 
through a public constructor
+     * @throws InstantiationException      if the provided class is abstract 
or an interface
+     * @throws InvocationTargetException   if there was an exception whilst 
constructing the class
      * @since 2.1
      */
-    public static <T> T newCheckedInstanceOf(final String className, final 
Class<T> clazz)
-            throws ClassNotFoundException, InvocationTargetException, 
InstantiationException,
-            IllegalAccessException {
+    public static <T> T newCheckedInstanceOf(final String className, final 
Class<T> clazz) throws ClassNotFoundException,
+            InvocationTargetException, InstantiationException, 
IllegalAccessException, NoSuchMethodException {
         return newInstanceOf(loadClass(className).asSubclass(clazz));
     }
 
     /**
-     * Loads and instantiates a class given by a property name.
+     * Loads the provided class by name as a checked subtype of the given 
class. All checked reflective operation
+     * exceptions are translated into corresponding {@link LinkageError} 
classes.
      *
-     * @param propertyName The property name to look up a class name for.
-     * @param clazz        The class to cast it to.
-     * @param <T>          The type to cast it to.
-     * @return new instance of the class given in the property or {@code null} 
if the property was unset.
-     * @throws ClassNotFoundException    if the class isn't available to the 
usual ClassLoaders
-     * @throws IllegalAccessException    if the class can't be instantiated 
through a public constructor
-     * @throws InstantiationException    if there was an exception whilst 
instantiating the class
-     * @throws InvocationTargetException if there was an exception whilst 
constructing the class
-     * @throws ClassCastException        if the constructed object isn't type 
compatible with {@code T}
-     * @since 2.5
+     * @param className fully qualified class name to load
+     * @param supertype supertype of the class being loaded
+     * @param <T>       type of instance to return
+     * @return new instance of the requested class
+     * @throws NoClassDefFoundError        if the provided class name could 
not be found
+     * @throws ExceptionInInitializerError if an exception is thrown during 
class initialization
+     * @throws ClassCastException          if the loaded class is not a 
subtype of the provided class
+     * @throws NoSuchMethodError           if no zero-arg constructor exists
+     * @throws SecurityException           if this class is not allowed to 
access declared members of the provided class
+     * @throws InternalException           if an exception is thrown by the 
constructor
+     * @throws InstantiationError          if the provided class is abstract 
or an interface
+     * @throws IllegalAccessError          if the class cannot be accessed
+     * @throws LinkageError                if the linkage of the class fails 
for any other reason
+     * @since 3.0.0
      */
-    public static <T> T newCheckedInstanceOfProperty(final String 
propertyName, final Class<T> clazz)
-        throws ClassNotFoundException, InvocationTargetException, 
InstantiationException,
-        IllegalAccessException {
-        final String className = 
PropertiesUtil.getProperties().getStringProperty(propertyName);
-        if (className == null) {
-            return null;
-        }
-        return newCheckedInstanceOf(className, clazz);
+    public static <T> T newInstanceOfUnchecked(final String className, final 
Class<T> supertype) {
+        final Class<? extends T> clazz = 
loadClassUnchecked(className).asSubclass(supertype);
+        return newInstanceOfUnchecked(clazz);
     }
 
     private static boolean isIgnoreTccl() {
@@ -330,11 +447,13 @@ public final class LoaderUtil {
     private static boolean isForceTccl() {
         if (forceTcclOnly == null) {
             // PropertiesUtil.getProperties() uses that code path so don't use 
that!
+            final String key = 
LoggingSystemProperty.LOADER_FORCE_THREAD_CONTEXT_LOADER.getSystemKey();
+            final SecurityManager securityManager = 
System.getSecurityManager();
             try {
-                forceTcclOnly = System.getSecurityManager() == null ?
-                    
Boolean.getBoolean(LoggingSystemProperty.LOADER_FORCE_THREAD_CONTEXT_LOADER.getSystemKey())
 :
-                    AccessController.doPrivileged((PrivilegedAction<Boolean>) 
() -> Boolean.getBoolean(
-                            
LoggingSystemProperty.LOADER_FORCE_THREAD_CONTEXT_LOADER.getSystemKey()));
+                if (securityManager != null) {
+                    securityManager.checkPropertyAccess(key);
+                }
+                forceTcclOnly = Boolean.getBoolean(key);
             } catch (final SecurityException se) {
                 forceTcclOnly = false;
             }
@@ -350,11 +469,7 @@ public final class LoaderUtil {
      * @since 2.1
      */
     public static Collection<URL> findResources(final String resource) {
-        return findResources(resource, true);
-    }
-
-    public static Collection<URL> findResources(final String resource, final 
boolean useTccl) {
-        final Collection<UrlResource> urlResources = 
findUrlResources(resource, useTccl);
+        final Collection<UrlResource> urlResources = 
findUrlResources(resource);
         final Collection<URL> resources = new 
LinkedHashSet<>(urlResources.size());
         for (final UrlResource urlResource : urlResources) {
             resources.add(urlResource.getUrl());
@@ -366,18 +481,13 @@ public final class LoaderUtil {
      * This method will only find resources that follow the JPMS rules for 
encapsulation. Resources
      * on the class path should be found as normal along with resources with 
no package name in all
      * modules. Resources within packages in modules must declare those 
resources open to org.apache.logging.log4j.
+     *
      * @param resource The resource to locate.
      * @return The located resources.
      */
-    public static Collection<UrlResource> findUrlResources(final String 
resource, final boolean useTccl) {
-        // @formatter:off
-        final ClassLoader[] candidates = {
-                getThreadContextClassLoader(),
-                isForceTccl() ? null : LoaderUtil.class.getClassLoader(),
-                isForceTccl() || GET_CLASS_LOADER_DISABLED ? null : 
ClassLoader.getSystemClassLoader()};
-        // @formatter:on
+    public static Collection<UrlResource> findUrlResources(final String 
resource) {
         final Collection<UrlResource> resources = new LinkedHashSet<>();
-        for (final ClassLoader cl : candidates) {
+        for (final ClassLoader cl : getClassLoaders()) {
             if (cl != null) {
                 try {
                     final Enumeration<URL> resourceEnum = 
cl.getResources(resource);
@@ -423,10 +533,7 @@ public final class LoaderUtil {
 
             final UrlResource that = (UrlResource) o;
 
-            if (classLoader != null ? !classLoader.equals(that.classLoader) : 
that.classLoader != null) {
-                return false;
-            }
-            return url != null ? url.equals(that.url) : that.url == null;
+            return Objects.equals(classLoader, that.classLoader) && 
Objects.equals(url, that.url);
         }
 
         @Override
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 e777f03ef0..58077430f4 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
@@ -112,12 +112,12 @@ public class PropertiesUtil implements 
PropertyEnvironment {
     private PropertiesUtil(final String contextName, final String 
propertiesFileName, final boolean useTccl) {
         final List<PropertySource> sources = new ArrayList<>();
         if (propertiesFileName.endsWith(".json") || 
propertiesFileName.endsWith(".jsn")) {
-            final PropertySource source = 
getJsonPropertySource(propertiesFileName, useTccl, 50);
+            final PropertySource source = 
getJsonPropertySource(propertiesFileName, 50);
             if (source != null) {
                 sources.add(source);
             }
         } else {
-            final PropertySource source = new 
PropertiesPropertySource(PropertyFilePropertySource.loadPropertiesFile(propertiesFileName,
 useTccl),
+            final PropertySource source = new 
PropertiesPropertySource(PropertyFilePropertySource.loadPropertiesFile(propertiesFileName),
                 null, 60, true);
             sources.add(source);
         }
@@ -173,10 +173,10 @@ public class PropertiesUtil implements 
PropertyEnvironment {
     private static Environment getEnvironment(final String namespace, final 
boolean useTccl) {
         final List<PropertySource> sources = new ArrayList<>();
         final String fileName = String.format("log4j2.%s.properties", 
namespace);
-        final Properties properties = 
PropertyFilePropertySource.loadPropertiesFile(fileName, useTccl);
+        final Properties properties = 
PropertyFilePropertySource.loadPropertiesFile(fileName);
         PropertySource source = new PropertiesPropertySource(properties, 50);
         sources.add(source);
-        source = getJsonPropertySource(String.format("log4j2.%s.json", 
namespace), useTccl, 60);
+        source = getJsonPropertySource(String.format("log4j2.%s.json", 
namespace), 60);
         if (source != null) {
             sources.add(source);
         }
@@ -344,7 +344,7 @@ public class PropertiesUtil implements PropertyEnvironment {
         return sources;
     }
 
-    private static PropertySource getJsonPropertySource(final String fileName, 
final boolean useTccl, int priority) {
+    private static PropertySource getJsonPropertySource(final String fileName, 
int priority) {
         if (fileName.startsWith("file://")) {
             try {
                 final URL url = new URL(fileName);
@@ -365,7 +365,7 @@ public class PropertiesUtil implements PropertyEnvironment {
                     LowLevelLogUtil.logException("Unable to read " + fileName, 
ioe);
                 }
             } else {
-                for (final URL url : LoaderUtil.findResources(fileName, 
useTccl)) {
+                for (final URL url : LoaderUtil.findResources(fileName)) {
                     try (final InputStream in = url.openStream()) {
                         return parseJsonProperties(new 
String(in.readAllBytes(),
                                 StandardCharsets.UTF_8), 
PropertySource.SYSTEM_CONTEXT, priority);
@@ -440,7 +440,7 @@ public class PropertiesUtil implements PropertyEnvironment {
 
         private Environment(final String contextName, final 
List<PropertySource> propertySources) {
             try {
-                final Properties sysProps = 
PropertyFilePropertySource.loadPropertiesFile(LOG4J_SYSTEM_PROPERTIES_FILE_NAME,
 false);
+                final Properties sysProps = 
PropertyFilePropertySource.loadPropertiesFile(LOG4J_SYSTEM_PROPERTIES_FILE_NAME);
                 for (String key : sysProps.stringPropertyNames()) {
                     if (System.getProperty(key) == null) {
                         System.setProperty(key, sysProps.getProperty(key));
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyFilePropertySource.java
 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyFilePropertySource.java
index dd08cf5d9d..7c10d4eee2 100644
--- 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyFilePropertySource.java
+++ 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/PropertyFilePropertySource.java
@@ -29,20 +29,16 @@ import java.util.Properties;
 public class PropertyFilePropertySource extends PropertiesPropertySource {
 
     public PropertyFilePropertySource(final String fileName) {
-        this(fileName, true, false);
+        this(fileName, false);
     }
 
-    public PropertyFilePropertySource(final String fileName, final boolean 
useTccl) {
-        this(fileName, useTccl, false);
+    public PropertyFilePropertySource(final String fileName, final boolean 
includeInvalid) {
+        super(loadPropertiesFile(fileName), SYSTEM_CONTEXT, 20, 
includeInvalid);
     }
 
-    public PropertyFilePropertySource(final String fileName, final boolean 
useTccl, final boolean includeInvalid) {
-        super(loadPropertiesFile(fileName, useTccl), SYSTEM_CONTEXT, 20, 
includeInvalid);
-    }
-
-    static Properties loadPropertiesFile(final String fileName, final boolean 
useTccl) {
+    static Properties loadPropertiesFile(final String fileName) {
         final Properties props = new Properties();
-        for (final URL url : LoaderUtil.findResources(fileName, useTccl)) {
+        for (final URL url : LoaderUtil.findResources(fileName)) {
             try (final InputStream in = url.openStream()) {
                 props.load(in);
             } catch (final IOException e) {


Reply via email to