Avoid UndeclaredThrowableStrategy with 1.8 bytecode level (CGLIB 3.3)
ClassLoaderAwareUndeclaredThrowableStrategy fails with a VerifyError on recent JDKs after the CGLIB 3.3 upgrade. The alternative is to replace it with a plain ClassLoaderAwareGeneratorStrategy (extracted from CglibSubclassingInstantiationStrategy) and custom UndeclaredThrowableException handling in CglibMethodInvocation. See gh-23453
This commit is contained in:
parent
561af5f8f9
commit
9bd3a535cd
|
@ -38,7 +38,7 @@ import org.springframework.aop.PointcutAdvisor;
|
|||
import org.springframework.aop.RawTargetAccess;
|
||||
import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.cglib.core.ClassGenerator;
|
||||
import org.springframework.cglib.core.ClassLoaderAwareGeneratorStrategy;
|
||||
import org.springframework.cglib.core.CodeGenerationException;
|
||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
|
@ -49,12 +49,12 @@ import org.springframework.cglib.proxy.Factory;
|
|||
import org.springframework.cglib.proxy.MethodInterceptor;
|
||||
import org.springframework.cglib.proxy.MethodProxy;
|
||||
import org.springframework.cglib.proxy.NoOp;
|
||||
import org.springframework.cglib.transform.impl.UndeclaredThrowableStrategy;
|
||||
import org.springframework.core.SmartClassLoader;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* CGLIB-based {@link AopProxy} implementation for the Spring AOP framework.
|
||||
|
@ -189,7 +189,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
|||
enhancer.setSuperclass(proxySuperClass);
|
||||
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
|
||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
|
||||
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
|
||||
|
||||
Callback[] callbacks = getCallbacks(rootClass);
|
||||
Class<?>[] types = new Class<?>[callbacks.length];
|
||||
|
@ -634,8 +634,8 @@ class CglibAopProxy implements AopProxy, Serializable {
|
|||
@Override
|
||||
@Nullable
|
||||
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
|
||||
MethodInvocation invocation = new CglibMethodInvocation(proxy, this.target, method, args,
|
||||
this.targetClass, this.adviceChain, methodProxy);
|
||||
MethodInvocation invocation = new CglibMethodInvocation(
|
||||
proxy, this.target, method, args, this.targetClass, this.adviceChain, methodProxy);
|
||||
// If we get here, we need to create a MethodInvocation.
|
||||
Object retVal = invocation.proceed();
|
||||
retVal = processReturnType(proxy, this.target, method, retVal);
|
||||
|
@ -740,6 +740,25 @@ class CglibAopProxy implements AopProxy, Serializable {
|
|||
methodProxy : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object proceed() throws Throwable {
|
||||
try {
|
||||
return super.proceed();
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
throw ex;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
|
||||
throw ex;
|
||||
}
|
||||
else {
|
||||
throw new UndeclaredThrowableException(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives a marginal performance improvement versus using reflection to
|
||||
* invoke the target when invoking public methods.
|
||||
|
@ -968,52 +987,4 @@ class CglibAopProxy implements AopProxy, Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CGLIB GeneratorStrategy variant which exposes the application ClassLoader
|
||||
* as thread context ClassLoader for the time of class generation
|
||||
* (in order for ASM to pick it up when doing common superclass resolution).
|
||||
*/
|
||||
private static class ClassLoaderAwareUndeclaredThrowableStrategy extends UndeclaredThrowableStrategy {
|
||||
|
||||
@Nullable
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public ClassLoaderAwareUndeclaredThrowableStrategy(@Nullable ClassLoader classLoader) {
|
||||
super(UndeclaredThrowableException.class);
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generate(ClassGenerator cg) throws Exception {
|
||||
if (this.classLoader == null) {
|
||||
return super.generate(cg);
|
||||
}
|
||||
|
||||
Thread currentThread = Thread.currentThread();
|
||||
ClassLoader threadContextClassLoader;
|
||||
try {
|
||||
threadContextClassLoader = currentThread.getContextClassLoader();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Cannot access thread context ClassLoader - falling back...
|
||||
return super.generate(cg);
|
||||
}
|
||||
|
||||
boolean overrideClassLoader = !this.classLoader.equals(threadContextClassLoader);
|
||||
if (overrideClassLoader) {
|
||||
currentThread.setContextClassLoader(this.classLoader);
|
||||
}
|
||||
try {
|
||||
return super.generate(cg);
|
||||
}
|
||||
finally {
|
||||
if (overrideClassLoader) {
|
||||
// Reset original thread context ClassLoader.
|
||||
currentThread.setContextClassLoader(threadContextClassLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -68,7 +68,7 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea
|
|||
|
||||
protected final Method method;
|
||||
|
||||
protected Object[] arguments = new Object[0];
|
||||
protected Object[] arguments;
|
||||
|
||||
@Nullable
|
||||
private final Class<?> targetClass;
|
||||
|
@ -158,7 +158,7 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea
|
|||
@Override
|
||||
@Nullable
|
||||
public Object proceed() throws Throwable {
|
||||
// We start with an index of -1 and increment early.
|
||||
// We start with an index of -1 and increment early.
|
||||
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
|
||||
return invokeJoinpoint();
|
||||
}
|
||||
|
|
|
@ -26,8 +26,7 @@ import org.springframework.beans.BeanInstantiationException;
|
|||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.cglib.core.ClassGenerator;
|
||||
import org.springframework.cglib.core.DefaultGeneratorStrategy;
|
||||
import org.springframework.cglib.core.ClassLoaderAwareGeneratorStrategy;
|
||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||
import org.springframework.cglib.proxy.Callback;
|
||||
import org.springframework.cglib.proxy.CallbackFilter;
|
||||
|
@ -187,53 +186,6 @@ public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationSt
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* CGLIB GeneratorStrategy variant which exposes the application ClassLoader
|
||||
* as thread context ClassLoader for the time of class generation
|
||||
* (in order for ASM to pick it up when doing common superclass resolution).
|
||||
*/
|
||||
private static class ClassLoaderAwareGeneratorStrategy extends DefaultGeneratorStrategy {
|
||||
|
||||
@Nullable
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public ClassLoaderAwareGeneratorStrategy(@Nullable ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generate(ClassGenerator cg) throws Exception {
|
||||
if (this.classLoader == null) {
|
||||
return super.generate(cg);
|
||||
}
|
||||
|
||||
Thread currentThread = Thread.currentThread();
|
||||
ClassLoader threadContextClassLoader;
|
||||
try {
|
||||
threadContextClassLoader = currentThread.getContextClassLoader();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Cannot access thread context ClassLoader - falling back...
|
||||
return super.generate(cg);
|
||||
}
|
||||
|
||||
boolean overrideClassLoader = !this.classLoader.equals(threadContextClassLoader);
|
||||
if (overrideClassLoader) {
|
||||
currentThread.setContextClassLoader(this.classLoader);
|
||||
}
|
||||
try {
|
||||
return super.generate(cg);
|
||||
}
|
||||
finally {
|
||||
if (overrideClassLoader) {
|
||||
// Reset original thread context ClassLoader.
|
||||
currentThread.setContextClassLoader(threadContextClassLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* CGLIB callback for filtering method interception behavior.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
/**
|
||||
* CGLIB GeneratorStrategy variant which exposes the application ClassLoader
|
||||
* as current thread context ClassLoader for the time of class generation.
|
||||
* The ASM ClassWriter in Spring's ASM variant will pick it up when doing
|
||||
* common superclass resolution.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 5.2
|
||||
*/
|
||||
public class ClassLoaderAwareGeneratorStrategy extends DefaultGeneratorStrategy {
|
||||
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
public ClassLoaderAwareGeneratorStrategy(ClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] generate(ClassGenerator cg) throws Exception {
|
||||
if (this.classLoader == null) {
|
||||
return super.generate(cg);
|
||||
}
|
||||
|
||||
Thread currentThread = Thread.currentThread();
|
||||
ClassLoader threadContextClassLoader;
|
||||
try {
|
||||
threadContextClassLoader = currentThread.getContextClassLoader();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Cannot access thread context ClassLoader - falling back...
|
||||
return super.generate(cg);
|
||||
}
|
||||
|
||||
boolean overrideClassLoader = !this.classLoader.equals(threadContextClassLoader);
|
||||
if (overrideClassLoader) {
|
||||
currentThread.setContextClassLoader(this.classLoader);
|
||||
}
|
||||
try {
|
||||
return super.generate(cg);
|
||||
}
|
||||
finally {
|
||||
if (overrideClassLoader) {
|
||||
// Reset original thread context ClassLoader.
|
||||
currentThread.setContextClassLoader(threadContextClassLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
* Spring's repackaging of
|
||||
* <a href="https://github.com/cglib/cglib">CGLIB 3.2</a>
|
||||
* <a href="https://github.com/cglib/cglib">CGLIB 3.3</a>
|
||||
* (with Spring-specific patches; for internal use only).
|
||||
*
|
||||
* <p>This repackaging technique avoids any potential conflicts with
|
||||
|
|
Loading…
Reference in New Issue