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.RawTargetAccess;
|
||||||
import org.springframework.aop.TargetSource;
|
import org.springframework.aop.TargetSource;
|
||||||
import org.springframework.aop.support.AopUtils;
|
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.CodeGenerationException;
|
||||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||||
import org.springframework.cglib.proxy.Callback;
|
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.MethodInterceptor;
|
||||||
import org.springframework.cglib.proxy.MethodProxy;
|
import org.springframework.cglib.proxy.MethodProxy;
|
||||||
import org.springframework.cglib.proxy.NoOp;
|
import org.springframework.cglib.proxy.NoOp;
|
||||||
import org.springframework.cglib.transform.impl.UndeclaredThrowableStrategy;
|
|
||||||
import org.springframework.core.SmartClassLoader;
|
import org.springframework.core.SmartClassLoader;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CGLIB-based {@link AopProxy} implementation for the Spring AOP framework.
|
* CGLIB-based {@link AopProxy} implementation for the Spring AOP framework.
|
||||||
|
@ -189,7 +189,7 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||||
enhancer.setSuperclass(proxySuperClass);
|
enhancer.setSuperclass(proxySuperClass);
|
||||||
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
|
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
|
||||||
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
|
||||||
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
|
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
|
||||||
|
|
||||||
Callback[] callbacks = getCallbacks(rootClass);
|
Callback[] callbacks = getCallbacks(rootClass);
|
||||||
Class<?>[] types = new Class<?>[callbacks.length];
|
Class<?>[] types = new Class<?>[callbacks.length];
|
||||||
|
@ -634,8 +634,8 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
|
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
|
||||||
MethodInvocation invocation = new CglibMethodInvocation(proxy, this.target, method, args,
|
MethodInvocation invocation = new CglibMethodInvocation(
|
||||||
this.targetClass, this.adviceChain, methodProxy);
|
proxy, this.target, method, args, this.targetClass, this.adviceChain, methodProxy);
|
||||||
// If we get here, we need to create a MethodInvocation.
|
// If we get here, we need to create a MethodInvocation.
|
||||||
Object retVal = invocation.proceed();
|
Object retVal = invocation.proceed();
|
||||||
retVal = processReturnType(proxy, this.target, method, retVal);
|
retVal = processReturnType(proxy, this.target, method, retVal);
|
||||||
|
@ -740,6 +740,25 @@ class CglibAopProxy implements AopProxy, Serializable {
|
||||||
methodProxy : null);
|
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
|
* Gives a marginal performance improvement versus using reflection to
|
||||||
* invoke the target when invoking public methods.
|
* 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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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 final Method method;
|
||||||
|
|
||||||
protected Object[] arguments = new Object[0];
|
protected Object[] arguments;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private final Class<?> targetClass;
|
private final Class<?> targetClass;
|
||||||
|
@ -158,7 +158,7 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea
|
||||||
@Override
|
@Override
|
||||||
@Nullable
|
@Nullable
|
||||||
public Object proceed() throws Throwable {
|
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) {
|
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
|
||||||
return invokeJoinpoint();
|
return invokeJoinpoint();
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,7 @@ import org.springframework.beans.BeanInstantiationException;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.cglib.core.ClassGenerator;
|
import org.springframework.cglib.core.ClassLoaderAwareGeneratorStrategy;
|
||||||
import org.springframework.cglib.core.DefaultGeneratorStrategy;
|
|
||||||
import org.springframework.cglib.core.SpringNamingPolicy;
|
import org.springframework.cglib.core.SpringNamingPolicy;
|
||||||
import org.springframework.cglib.proxy.Callback;
|
import org.springframework.cglib.proxy.Callback;
|
||||||
import org.springframework.cglib.proxy.CallbackFilter;
|
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.
|
* 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
|
* 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).
|
* (with Spring-specific patches; for internal use only).
|
||||||
*
|
*
|
||||||
* <p>This repackaging technique avoids any potential conflicts with
|
* <p>This repackaging technique avoids any potential conflicts with
|
||||||
|
|
Loading…
Reference in New Issue