HHH-16400 Avoid reflection for calls to StackWalker

This commit is contained in:
Yoann Rodière 2023-03-30 17:04:34 +02:00 committed by Christian Beikov
parent 6ddf354b98
commit 5f0b571df6
1 changed files with 13 additions and 57 deletions

View File

@ -6,7 +6,6 @@
*/ */
package org.hibernate.bytecode.internal.bytebuddy; package org.hibernate.bytecode.internal.bytebuddy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
@ -99,37 +98,11 @@ public class HibernateMethodLookupDispatcher {
PrivilegedAction<PrivilegedAction<Class<?>[]>> initializeGetCallerStackAction = new PrivilegedAction<PrivilegedAction<Class<?>[]>>() { PrivilegedAction<PrivilegedAction<Class<?>[]>> initializeGetCallerStackAction = new PrivilegedAction<PrivilegedAction<Class<?>[]>>() {
@Override @Override
public PrivilegedAction<Class<?>[]> run() { public PrivilegedAction<Class<?>[]> run() {
Class<?> stackWalkerClass = null;
try { try {
// JDK 9 introduced the StackWalker return new StackWalkerGetCallerStackAction(StackWalker.getInstance( StackWalker.Option.RETAIN_CLASS_REFERENCE) );
stackWalkerClass = Class.forName( "java.lang.StackWalker" );
} }
catch (ClassNotFoundException e) { catch (Throwable e) {
// ignore, we will deal with that later. throw new HibernateException( "Unable to initialize the stack walker", e );
}
if ( stackWalkerClass != null ) {
// We can use a stack walker
try {
Class<?> optionClass = Class.forName( "java.lang.StackWalker$Option" );
Object stackWalker = stackWalkerClass.getMethod( "getInstance", optionClass )
// The first one is RETAIN_CLASS_REFERENCE
.invoke( null, optionClass.getEnumConstants()[0] );
Method stackWalkerWalkMethod = stackWalkerClass.getMethod( "walk", Function.class );
Method stackFrameGetDeclaringClass = Class.forName( "java.lang.StackWalker$StackFrame" )
.getMethod( "getDeclaringClass" );
return new StackWalkerGetCallerStackAction(
stackWalker, stackWalkerWalkMethod,stackFrameGetDeclaringClass
);
}
catch (Throwable e) {
throw new HibernateException( "Unable to initialize the stack walker", e );
}
}
else {
// We cannot use a stack walker, default to fetching the security manager class context
return new SecurityManagerClassContextGetCallerStackAction();
} }
} }
}; };
@ -165,59 +138,42 @@ public class HibernateMethodLookupDispatcher {
throw new SecurityException( "Unable to determine the caller class" ); throw new SecurityException( "Unable to determine the caller class" );
} }
/**
* A privileged action that retrieves the caller stack from the security manager class context.
*/
private static class SecurityManagerClassContextGetCallerStackAction extends SecurityManager
implements PrivilegedAction<Class<?>[]> {
@Override
public Class<?>[] run() {
return getClassContext();
}
}
/** /**
* A privileged action that retrieves the caller stack using a stack walker. * A privileged action that retrieves the caller stack using a stack walker.
*/ */
private static class StackWalkerGetCallerStackAction implements PrivilegedAction<Class<?>[]> { private static class StackWalkerGetCallerStackAction implements PrivilegedAction<Class<?>[]> {
private final Object stackWalker; private final StackWalker stackWalker;
private final Method stackWalkerWalkMethod;
private final Method stackFrameGetDeclaringClass;
StackWalkerGetCallerStackAction(Object stackWalker, Method stackWalkerWalkMethod, StackWalkerGetCallerStackAction(StackWalker stackWalker) {
Method stackFrameGetDeclaringClass) {
this.stackWalker = stackWalker; this.stackWalker = stackWalker;
this.stackWalkerWalkMethod = stackWalkerWalkMethod;
this.stackFrameGetDeclaringClass = stackFrameGetDeclaringClass;
} }
@Override @Override
public Class<?>[] run() { public Class<?>[] run() {
try { try {
return (Class<?>[]) stackWalkerWalkMethod.invoke( stackWalker, stackFrameExtractFunction ); return stackWalker.walk( stackFrameExtractFunction );
} }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { catch (RuntimeException e) {
throw new SecurityException( "Unable to determine the caller class", e ); throw new SecurityException( "Unable to determine the caller class", e );
} }
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) private final Function<Stream<StackWalker.StackFrame>, Class<?>[]> stackFrameExtractFunction = new Function<>() {
private final Function<Stream, Object> stackFrameExtractFunction = new Function<Stream, Object>() {
@Override @Override
public Object apply(Stream stream) { public Class<?>[] apply(Stream<StackWalker.StackFrame> stream) {
return stream.map( stackFrameGetDeclaringClassFunction ) return stream.map( stackFrameGetDeclaringClassFunction )
.limit( MAX_STACK_FRAMES ) .limit( MAX_STACK_FRAMES )
.toArray( Class<?>[]::new ); .toArray( Class<?>[]::new );
} }
}; };
private final Function<Object, Class<?>> stackFrameGetDeclaringClassFunction = new Function<Object, Class<?>>() { private final Function<StackWalker.StackFrame, Class<?>> stackFrameGetDeclaringClassFunction = new Function<>() {
@Override @Override
public Class<?> apply(Object t) { public Class<?> apply(StackWalker.StackFrame frame) {
try { try {
return (Class<?>) stackFrameGetDeclaringClass.invoke( t ); return frame.getDeclaringClass();
} }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { catch (RuntimeException e) {
throw new HibernateException( "Unable to get stack frame declaring class", e ); throw new HibernateException( "Unable to get stack frame declaring class", e );
} }
} }