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;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
@ -99,37 +98,11 @@ public class HibernateMethodLookupDispatcher {
PrivilegedAction<PrivilegedAction<Class<?>[]>> initializeGetCallerStackAction = new PrivilegedAction<PrivilegedAction<Class<?>[]>>() {
@Override
public PrivilegedAction<Class<?>[]> run() {
Class<?> stackWalkerClass = null;
try {
// JDK 9 introduced the StackWalker
stackWalkerClass = Class.forName( "java.lang.StackWalker" );
return new StackWalkerGetCallerStackAction(StackWalker.getInstance( StackWalker.Option.RETAIN_CLASS_REFERENCE) );
}
catch (ClassNotFoundException e) {
// ignore, we will deal with that later.
}
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();
catch (Throwable e) {
throw new HibernateException( "Unable to initialize the stack walker", e );
}
}
};
@ -165,59 +138,42 @@ public class HibernateMethodLookupDispatcher {
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.
*/
private static class StackWalkerGetCallerStackAction implements PrivilegedAction<Class<?>[]> {
private final Object stackWalker;
private final Method stackWalkerWalkMethod;
private final Method stackFrameGetDeclaringClass;
private final StackWalker stackWalker;
StackWalkerGetCallerStackAction(Object stackWalker, Method stackWalkerWalkMethod,
Method stackFrameGetDeclaringClass) {
StackWalkerGetCallerStackAction(StackWalker stackWalker) {
this.stackWalker = stackWalker;
this.stackWalkerWalkMethod = stackWalkerWalkMethod;
this.stackFrameGetDeclaringClass = stackFrameGetDeclaringClass;
}
@Override
public Class<?>[] run() {
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 );
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private final Function<Stream, Object> stackFrameExtractFunction = new Function<Stream, Object>() {
private final Function<Stream<StackWalker.StackFrame>, Class<?>[]> stackFrameExtractFunction = new Function<>() {
@Override
public Object apply(Stream stream) {
public Class<?>[] apply(Stream<StackWalker.StackFrame> stream) {
return stream.map( stackFrameGetDeclaringClassFunction )
.limit( MAX_STACK_FRAMES )
.toArray( Class<?>[]::new );
}
};
private final Function<Object, Class<?>> stackFrameGetDeclaringClassFunction = new Function<Object, Class<?>>() {
private final Function<StackWalker.StackFrame, Class<?>> stackFrameGetDeclaringClassFunction = new Function<>() {
@Override
public Class<?> apply(Object t) {
public Class<?> apply(StackWalker.StackFrame frame) {
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 );
}
}