Defensively handle fast class generation failure for individual methods
Includes rethrowing of last actual defineClass exception encountered. Closes gh-27490
This commit is contained in:
parent
bfa01b35df
commit
a295a28e4b
|
@ -679,13 +679,19 @@ class CglibAopProxy implements AopProxy, Serializable {
|
|||
Object retVal;
|
||||
// Check whether we only have one InvokerInterceptor: that is,
|
||||
// no real advice, but just reflective invocation of the target.
|
||||
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
|
||||
if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
|
||||
// We can skip creating a MethodInvocation: just invoke the target directly.
|
||||
// Note that the final invoker must be an InvokerInterceptor, so we know
|
||||
// it does nothing but a reflective operation on the target, and no hot
|
||||
// swapping or fancy proxying.
|
||||
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
|
||||
retVal = methodProxy.invoke(target, argsToUse);
|
||||
try {
|
||||
retVal = methodProxy.invoke(target, argsToUse);
|
||||
}
|
||||
catch (CodeGenerationException ex) {
|
||||
CglibMethodInvocation.logFastClassGenerationFailure(method);
|
||||
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We need to create a method invocation...
|
||||
|
@ -737,10 +743,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
|||
super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
|
||||
|
||||
// Only use method proxy for public methods not derived from java.lang.Object
|
||||
this.methodProxy = (Modifier.isPublic(method.getModifiers()) &&
|
||||
method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
|
||||
!AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method) ?
|
||||
methodProxy : null);
|
||||
this.methodProxy = (isMethodProxyCompatible(method) ? methodProxy : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -776,10 +779,25 @@ class CglibAopProxy implements AopProxy, Serializable {
|
|||
@Override
|
||||
protected Object invokeJoinpoint() throws Throwable {
|
||||
if (this.methodProxy != null) {
|
||||
return this.methodProxy.invoke(this.target, this.arguments);
|
||||
try {
|
||||
return this.methodProxy.invoke(this.target, this.arguments);
|
||||
}
|
||||
catch (CodeGenerationException ex) {
|
||||
logFastClassGenerationFailure(this.method);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return super.invokeJoinpoint();
|
||||
return super.invokeJoinpoint();
|
||||
}
|
||||
|
||||
static boolean isMethodProxyCompatible(Method method) {
|
||||
return (Modifier.isPublic(method.getModifiers()) &&
|
||||
method.getDeclaringClass() != Object.class && !AopUtils.isEqualsMethod(method) &&
|
||||
!AopUtils.isHashCodeMethod(method) && !AopUtils.isToStringMethod(method));
|
||||
}
|
||||
|
||||
static void logFastClassGenerationFailure(Method method) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Failed to generate CGLIB fast class for method: " + method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,17 +63,16 @@ public class ReflectUtils {
|
|||
|
||||
private static final Method classLoaderDefineClassMethod;
|
||||
|
||||
private static final ProtectionDomain PROTECTION_DOMAIN;
|
||||
|
||||
private static final Throwable THROWABLE;
|
||||
|
||||
private static final ProtectionDomain PROTECTION_DOMAIN;
|
||||
|
||||
private static final List<Method> OBJECT_METHODS = new ArrayList<Method>();
|
||||
|
||||
static {
|
||||
Method privateLookupIn;
|
||||
Method lookupDefineClass;
|
||||
Method classLoaderDefineClass;
|
||||
ProtectionDomain protectionDomain;
|
||||
Throwable throwable = null;
|
||||
try {
|
||||
privateLookupIn = (Method) AccessController.doPrivileged(new PrivilegedExceptionAction() {
|
||||
|
@ -102,39 +101,37 @@ public class ReflectUtils {
|
|||
String.class, byte[].class, Integer.TYPE, Integer.TYPE, ProtectionDomain.class);
|
||||
}
|
||||
});
|
||||
protectionDomain = getProtectionDomain(ReflectUtils.class);
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction() {
|
||||
public Object run() throws Exception {
|
||||
Method[] methods = Object.class.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
if ("finalize".equals(method.getName())
|
||||
|| (method.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) > 0) {
|
||||
continue;
|
||||
}
|
||||
OBJECT_METHODS.add(method);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Throwable t) {
|
||||
privateLookupIn = null;
|
||||
lookupDefineClass = null;
|
||||
classLoaderDefineClass = null;
|
||||
protectionDomain = null;
|
||||
throwable = t;
|
||||
}
|
||||
|
||||
privateLookupInMethod = privateLookupIn;
|
||||
lookupDefineClassMethod = lookupDefineClass;
|
||||
classLoaderDefineClassMethod = classLoaderDefineClass;
|
||||
PROTECTION_DOMAIN = protectionDomain;
|
||||
THROWABLE = throwable;
|
||||
PROTECTION_DOMAIN = getProtectionDomain(ReflectUtils.class);
|
||||
|
||||
AccessController.doPrivileged(new PrivilegedAction() {
|
||||
public Object run() {
|
||||
Method[] methods = Object.class.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
if ("finalize".equals(method.getName())
|
||||
|| (method.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) > 0) {
|
||||
continue;
|
||||
}
|
||||
OBJECT_METHODS.add(method);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
// SPRING PATCH END
|
||||
|
||||
private static final String[] CGLIB_PACKAGES = {
|
||||
"java.lang",
|
||||
};
|
||||
private static final String[] CGLIB_PACKAGES = {"java.lang"};
|
||||
|
||||
static {
|
||||
primitives.put("byte", Byte.TYPE);
|
||||
|
@ -499,6 +496,7 @@ public class ReflectUtils {
|
|||
ProtectionDomain protectionDomain, Class<?> contextClass) throws Exception {
|
||||
|
||||
Class c = null;
|
||||
Throwable t = THROWABLE;
|
||||
|
||||
// Preferred option: JDK 9+ Lookup.defineClass API if ClassLoader matches
|
||||
if (contextClass != null && contextClass.getClassLoader() == loader &&
|
||||
|
@ -516,6 +514,7 @@ public class ReflectUtils {
|
|||
// in case of plain LinkageError (class already defined)
|
||||
// or IllegalArgumentException (class in different package):
|
||||
// fall through to traditional ClassLoader.defineClass below
|
||||
t = ex;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new CodeGenerationException(ex);
|
||||
|
@ -539,9 +538,11 @@ public class ReflectUtils {
|
|||
throw new CodeGenerationException(ex.getTargetException());
|
||||
}
|
||||
// in case of UnsupportedOperationException, fall through
|
||||
t = ex.getTargetException();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// publicDefineClass method not available -> fall through
|
||||
t = ex;
|
||||
}
|
||||
|
||||
// Classic option: protected ClassLoader.defineClass method
|
||||
|
@ -562,6 +563,7 @@ public class ReflectUtils {
|
|||
if (!ex.getClass().getName().endsWith("InaccessibleObjectException")) {
|
||||
throw new CodeGenerationException(ex);
|
||||
}
|
||||
t = ex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -584,7 +586,7 @@ public class ReflectUtils {
|
|||
|
||||
// No defineClass variant available at all?
|
||||
if (c == null) {
|
||||
throw new CodeGenerationException(THROWABLE);
|
||||
throw new CodeGenerationException(t);
|
||||
}
|
||||
|
||||
// Force static initializers to run.
|
||||
|
|
Loading…
Reference in New Issue