You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2022/01/08 14:30:25 UTC

[logging-log4j2] 01/02: Add StackLocatorUtil.getCallerClassLoader(int) for the 1.2 bridge.

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

ggregory pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit 6c6b0a20da76453bfdb72f402dc40e5eeda4e5f9
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Sat Jan 8 09:30:04 2022 -0500

    Add StackLocatorUtil.getCallerClassLoader(int) for the 1.2 bridge.
    
    - Add some Javadocs.
    - Fix error message to not mention Java 7 versions.
    - Normalize constant name.
    - Remove single use local variable.
    - Split commit for cherry-picking to master.
---
 .../apache/logging/log4j/util/StackLocator.java    | 69 ++++++++++++++--------
 .../logging/log4j/util/StackLocatorUtil.java       | 22 +++++++
 2 files changed, 65 insertions(+), 26 deletions(-)

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 1e50aa9..495b66f 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
@@ -47,46 +47,50 @@ import java.util.function.Predicate;
  */
 public final class StackLocator {
 
-    // Checkstyle Suppress: the lower-case 'u' ticks off CheckStyle...
-    // CHECKSTYLE:OFF
-    static final int JDK_7u25_OFFSET;
-    // CHECKSTYLE:OFF
+    /** TODO Consider removing now that we require Java 8. */
+    static final int JDK_7U25_OFFSET;
 
-    private static final Method GET_CALLER_CLASS;
+    private static final Method GET_CALLER_CLASS_METHOD;
 
     private static final StackLocator INSTANCE;
+    
+    /** TODO: Use Object.class. */
+    private static final Class<?> DEFAULT_CALLER_CLASS = null;
 
     static {
-        Method getCallerClass;
+        Method getCallerClassMethod;
         int java7u25CompensationOffset = 0;
         try {
             final Class<?> sunReflectionClass = LoaderUtil.loadClass("sun.reflect.Reflection");
-            getCallerClass = sunReflectionClass.getDeclaredMethod("getCallerClass", int.class);
-            Object o = getCallerClass.invoke(null, 0);
-            getCallerClass.invoke(null, 0);
+            getCallerClassMethod = sunReflectionClass.getDeclaredMethod("getCallerClass", int.class);
+            Object o = getCallerClassMethod.invoke(null, 0);
+            getCallerClassMethod.invoke(null, 0);
             if (o == null || o != sunReflectionClass) {
-                getCallerClass = null;
+                getCallerClassMethod = null;
                 java7u25CompensationOffset = -1;
             } else {
-                o = getCallerClass.invoke(null, 1);
+                o = getCallerClassMethod.invoke(null, 1);
                 if (o == sunReflectionClass) {
-                    System.out.println("WARNING: Java 1.7.0_25 is in use which has a broken implementation of Reflection.getCallerClass(). " +
-                        " Please consider upgrading to Java 1.7.0_40 or later.");
+                    System.out.println("WARNING: Unexpected result from sun.reflect.Reflection.getCallerClass(int), adjusting offset for future calls.");
                     java7u25CompensationOffset = 1;
                 }
             }
         } catch (final Exception | LinkageError e) {
             System.out.println("WARNING: sun.reflect.Reflection.getCallerClass is not supported. This will impact performance.");
-            getCallerClass = null;
+            getCallerClassMethod = null;
             java7u25CompensationOffset = -1;
         }
 
-        GET_CALLER_CLASS = getCallerClass;
-        JDK_7u25_OFFSET = java7u25CompensationOffset;
-
+        GET_CALLER_CLASS_METHOD = getCallerClassMethod;
+        JDK_7U25_OFFSET = java7u25CompensationOffset;
         INSTANCE = new StackLocator();
     }
 
+    /**
+     * Gets the singleton instance.
+     *
+     * @return the singleton instance.
+     */
     public static StackLocator getInstance() {
         return INSTANCE;
     }
@@ -114,26 +118,41 @@ public final class StackLocator {
                 return clazz;
             }
         }
-        return null;
+        return DEFAULT_CALLER_CLASS;
     }
 
+    /**
+     * Gets the Class of the method that called <em>this</em> method at the location up the call stack by the given stack
+     * frame depth.
+     * <p>
+     * This method returns {@code null} if:
+     * </p>
+     * <ul>
+     * <li>{@code sun.reflect.Reflection.getCallerClass(int)} is not present.</li>
+     * <li>An exception is caught calling {@code sun.reflect.Reflection.getCallerClass(int)}.</li>
+     * </ul>
+     *
+     * @param depth The stack frame count to walk.
+     * @return A class or null.
+     * @throws IndexOutOfBoundsException if depth is negative.
+     */
     // migrated from ReflectiveCallerClassUtility
     @PerformanceSensitive
     public Class<?> getCallerClass(final int depth) {
         if (depth < 0) {
             throw new IndexOutOfBoundsException(Integer.toString(depth));
         }
-        if (GET_CALLER_CLASS == null) {
-            return null;
+        if (GET_CALLER_CLASS_METHOD == null) {
+            return DEFAULT_CALLER_CLASS;
         }
         // note that we need to add 1 to the depth value to compensate for this method, but not for the Method.invoke
         // since Reflection.getCallerClass ignores the call to Method.invoke()
         try {
-            return (Class<?>) GET_CALLER_CLASS.invoke(null, depth + 1 + JDK_7u25_OFFSET);
+            return (Class<?>) GET_CALLER_CLASS_METHOD.invoke(null, depth + 1 + JDK_7U25_OFFSET);
         } catch (final Exception e) {
             // theoretically this could happen if the caller class were native code
             // TODO: return Object.class
-            return null;
+            return DEFAULT_CALLER_CLASS;
         }
     }
 
@@ -152,7 +171,7 @@ public final class StackLocator {
             }
         }
         // TODO: return Object.class
-        return null;
+        return DEFAULT_CALLER_CLASS;
     }
 
     // added for use in LoggerAdapter implementations mainly
@@ -198,7 +217,6 @@ public final class StackLocator {
         for (int i = 0; i < stackTrace.length; i++) {
             final String className = stackTrace[i].getClassName();
             if (fqcnOfLogger.equals(className)) {
-
                 found = true;
                 continue;
             }
@@ -212,9 +230,8 @@ public final class StackLocator {
     public StackTraceElement getStackTraceElement(final int depth) {
         // (MS) I tested the difference between using Throwable.getStackTrace() and Thread.getStackTrace(), and
         // the version using Throwable was surprisingly faster! at least on Java 1.8. See ReflectionBenchmark.
-        final StackTraceElement[] elements = new Throwable().getStackTrace();
         int i = 0;
-        for (final StackTraceElement element : elements) {
+        for (final StackTraceElement element : new Throwable().getStackTrace()) {
             if (isValid(element)) {
                 if (i == depth) {
                     return element;
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocatorUtil.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocatorUtil.java
index 72f181d..6f8a388 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocatorUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/StackLocatorUtil.java
@@ -71,6 +71,28 @@ public final class StackLocatorUtil {
     }
 
     /**
+     * Gets the ClassLoader of the class that called <em>this</em> method at the location up the call stack by the given
+     * stack frame depth.
+     * <p>
+     * This method returns {@code null} if:
+     * </p>
+     * <ul>
+     * <li>{@code sun.reflect.Reflection.getCallerClass(int)} is not present.</li>
+     * <li>An exception is caught calling {@code sun.reflect.Reflection.getCallerClass(int)}.</li>
+     * <li>Some Class implementations may use null to represent the bootstrap class loader.</li>
+     * </ul>
+     *
+     * @param depth The stack frame count to walk.
+     * @return A class or null.
+     * @throws IndexOutOfBoundsException if depth is negative.
+     */
+    @PerformanceSensitive
+    public static ClassLoader getCallerClassLoader(final int depth) {
+        final Class<?> callerClass = stackLocator.getCallerClass(depth + 1);
+        return callerClass != null ? callerClass.getClassLoader() : null;
+    }
+
+    /**
      * Search for a calling class.
      *
      * @param sentinelClass Sentinel class at which to begin searching