Repository: logging-log4j2
Updated Branches:
  refs/heads/master 014300908 -> 90e8e6053


[LOG4J2-1763]: Use MethodHandle in ReflectionUtil

Using a baseline of JDK 7, we can use MethodHandle instead of Method for
faster reflection in this performance-sensitive class.


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/90e8e605
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/90e8e605
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/90e8e605

Branch: refs/heads/master
Commit: 90e8e60530df52b005560f1aa5116602fe1503f9
Parents: 0143009
Author: Matt Sicker <[email protected]>
Authored: Tue Jan 3 20:59:59 2017 -0600
Committer: Matt Sicker <[email protected]>
Committed: Tue Jan 3 20:59:59 2017 -0600

----------------------------------------------------------------------
 .../logging/log4j/util/ReflectionUtil.java      | 45 +++++++++++---------
 src/changes/changes.xml                         |  3 ++
 2 files changed, 29 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/90e8e605/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
----------------------------------------------------------------------
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
index 52f171e..7506e75 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
@@ -16,7 +16,9 @@
  */
 package org.apache.logging.log4j.util;
 
-import java.lang.reflect.Method;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
 import java.util.Stack;
 
 import org.apache.logging.log4j.Logger;
@@ -32,6 +34,7 @@ import org.apache.logging.log4j.status.StatusLogger;
  * {@code Class} using the slow {@link Class#forName} (which can add an extra 
microsecond or more for each invocation
  * depending on the runtime ClassLoader hierarchy).
  * </p>
+ * <h3>History</h3>
  * <p>
  * During Java 8 development, the {@code 
sun.reflect.Reflection.getCallerClass(int)} was removed from OpenJDK, and this
  * change was back-ported to Java 7 in version 1.7.0_25 which changed the 
behavior of the call and caused it to be off
@@ -40,8 +43,9 @@ import org.apache.logging.log4j.status.StatusLogger;
  * </p>
  * <p>
  * After much community backlash, the JDK team agreed to restore {@code 
getCallerClass(int)} and keep its existing
- * behavior for the rest of Java 7. However, the method is deprecated in Java 
8, and current Java 9 development has not
- * addressed this API. Therefore, the functionality of this class cannot be 
relied upon for all future versions of Java.
+ * behavior for the rest of Java 7. However, the method is deprecated in Java 
8, and Java 9 provides a new API
+ * ({@code StackWalker}).
+ * Therefore, the functionality of this class cannot be relied upon for all 
future versions of Java.
  * It does, however, work just fine in Sun JDK 1.6, OpenJDK 1.6, 
Oracle/OpenJDK 1.7, and Oracle/OpenJDK 1.8. Other Java
  * environments may fall back to using {@link Throwable#getStackTrace()} which 
is significantly slower due to
  * examination of every virtual frame of execution.
@@ -52,29 +56,31 @@ public final class ReflectionUtil {
     // CHECKSTYLE:OFF
     static final int JDK_7u25_OFFSET;
     // CHECKSTYLE:OFF
-    
+
     private static final Logger LOGGER = StatusLogger.getLogger();
+
     private static final boolean SUN_REFLECTION_SUPPORTED;
-    private static final Method GET_CALLER_CLASS;
+    private static final MethodHandle GET_CALLER_CLASS;
     private static final PrivateSecurityManager SECURITY_MANAGER;
 
     static {
-        Method getCallerClass;
+        MethodHandle getCallerClass;
         int java7u25CompensationOffset = 0;
         try {
             final Class<?> sunReflectionClass = 
LoaderUtil.loadClass("sun.reflect.Reflection");
-            getCallerClass = 
sunReflectionClass.getDeclaredMethod("getCallerClass", int.class);
-            Object o = getCallerClass.invoke(null, 0);
-            final Object test1 = getCallerClass.invoke(null, 0);
+            getCallerClass = 
MethodHandles.lookup().findStatic(sunReflectionClass, "getCallerClass",
+                MethodType.methodType(Class.class, int.class));
+            Class<?> o = (Class<?>) getCallerClass.invokeExact(0);
+            final Class<?> test1 = (Class<?>) getCallerClass.invokeExact(0);
             if (o == null || o != sunReflectionClass) {
                 LOGGER.warn("Unexpected return value from 
Reflection.getCallerClass(): {}", test1);
                 getCallerClass = null;
                 java7u25CompensationOffset = -1;
             } else {
-                o = getCallerClass.invoke(null, 1);
+                o = (Class<?>) getCallerClass.invokeExact(1);
                 if (o == sunReflectionClass) {
                     LOGGER.warn("You are using Java 1.7.0_25 which has a 
broken implementation of "
-                            + "Reflection.getCallerClass.");
+                        + "Reflection.getCallerClass.");
                     LOGGER.warn("You should upgrade to at least Java 1.7.0_40 
or later.");
                     LOGGER.debug("Using stack depth compensation offset of 1 
due to Java 7u25.");
                     java7u25CompensationOffset = 1;
@@ -82,7 +88,11 @@ public final class ReflectionUtil {
             }
         } catch (final Exception | LinkageError e) {
             LOGGER.info("sun.reflect.Reflection.getCallerClass is not 
supported. "
-                    + "ReflectionUtil.getCallerClass will be much slower due 
to this.", e);
+                + "ReflectionUtil.getCallerClass will be much slower due to 
this.", e);
+            getCallerClass = null;
+            java7u25CompensationOffset = -1;
+        } catch (final Throwable throwable) {
+            LOGGER.warn("Error looking up 
sun.reflect.Reflection.getCallerClass", throwable);
             getCallerClass = null;
             java7u25CompensationOffset = -1;
         }
@@ -100,7 +110,7 @@ public final class ReflectionUtil {
             psm = new PrivateSecurityManager();
         } catch (final SecurityException ignored) {
             LOGGER.debug("Not allowed to create SecurityManager. "
-                    + "Falling back to slowest ReflectionUtil 
implementation.");
+                + "Falling back to slowest ReflectionUtil implementation.");
             psm = null;
         }
         SECURITY_MANAGER = psm;
@@ -126,8 +136,8 @@ public final class ReflectionUtil {
         // since Reflection.getCallerClass ignores the call to Method.invoke()
         if (supportsFastReflection()) {
             try {
-                return (Class<?>) GET_CALLER_CLASS.invoke(null, depth + 1 + 
JDK_7u25_OFFSET);
-            } catch (final Exception e) {
+                return (Class<?>) GET_CALLER_CLASS.invokeExact(depth + 1 + 
JDK_7u25_OFFSET);
+            } catch (final Throwable e) {
                 // theoretically this could happen if the caller class were 
native code
                 LOGGER.error("Error in ReflectionUtil.getCallerClass({}).", 
depth, e);
                 // TODO: return Object.class
@@ -255,7 +265,7 @@ public final class ReflectionUtil {
         }
         try {
             return LoaderUtil.loadClass(getCallerClassName(anchor.getName(), 
Strings.EMPTY,
-                    new Throwable().getStackTrace()));
+                new Throwable().getStackTrace()));
         } catch (final ClassNotFoundException ignored) {
             // no problem really
         }
@@ -302,9 +312,6 @@ public final class ReflectionUtil {
         return new Stack<>();
     }
 
-    /**
-     * 
-     */
     static final class PrivateSecurityManager extends SecurityManager {
 
         @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/90e8e605/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 4ae700d..905f9ae 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -222,6 +222,9 @@
       <action issue="LOG4J2-1302" dev="rpopma" type="update">
         The log4j-slf4j-impl module now declares a runtime dependency on 
log4j-core. While not technically required, this makes the log4j-slf4j-impl 
module behave similarly to slf4j-log4j12, and facilitates migration to Log4j 2.
       </action>
+      <action issue="LOG4J2-1763" dev="mattsicker" type="add">
+        Use MethodHandle instead of Method in ReflectionUtil.
+      </action>
       <action issue="LOG4J2-1730" dev="mattsicker" type="add">
         Add Apache Cassandra appender.
       </action>

Reply via email to