Skip to content

Commit 9bd3a53

Browse files
committed
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
1 parent 561af5f commit 9bd3a53

File tree

5 files changed

+96
-106
lines changed

5 files changed

+96
-106
lines changed

spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java

+24-53
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
import org.springframework.aop.RawTargetAccess;
3939
import org.springframework.aop.TargetSource;
4040
import org.springframework.aop.support.AopUtils;
41-
import org.springframework.cglib.core.ClassGenerator;
41+
import org.springframework.cglib.core.ClassLoaderAwareGeneratorStrategy;
4242
import org.springframework.cglib.core.CodeGenerationException;
4343
import org.springframework.cglib.core.SpringNamingPolicy;
4444
import org.springframework.cglib.proxy.Callback;
@@ -49,12 +49,12 @@
4949
import org.springframework.cglib.proxy.MethodInterceptor;
5050
import org.springframework.cglib.proxy.MethodProxy;
5151
import org.springframework.cglib.proxy.NoOp;
52-
import org.springframework.cglib.transform.impl.UndeclaredThrowableStrategy;
5352
import org.springframework.core.SmartClassLoader;
5453
import org.springframework.lang.Nullable;
5554
import org.springframework.util.Assert;
5655
import org.springframework.util.ClassUtils;
5756
import org.springframework.util.ObjectUtils;
57+
import org.springframework.util.ReflectionUtils;
5858

5959
/**
6060
* CGLIB-based {@link AopProxy} implementation for the Spring AOP framework.
@@ -189,7 +189,7 @@ public Object getProxy(@Nullable ClassLoader classLoader) {
189189
enhancer.setSuperclass(proxySuperClass);
190190
enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
191191
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
192-
enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
192+
enhancer.setStrategy(new ClassLoaderAwareGeneratorStrategy(classLoader));
193193

194194
Callback[] callbacks = getCallbacks(rootClass);
195195
Class<?>[] types = new Class<?>[callbacks.length];
@@ -634,8 +634,8 @@ public FixedChainStaticTargetInterceptor(
634634
@Override
635635
@Nullable
636636
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
637-
MethodInvocation invocation = new CglibMethodInvocation(proxy, this.target, method, args,
638-
this.targetClass, this.adviceChain, methodProxy);
637+
MethodInvocation invocation = new CglibMethodInvocation(
638+
proxy, this.target, method, args, this.targetClass, this.adviceChain, methodProxy);
639639
// If we get here, we need to create a MethodInvocation.
640640
Object retVal = invocation.proceed();
641641
retVal = processReturnType(proxy, this.target, method, retVal);
@@ -740,6 +740,25 @@ public CglibMethodInvocation(Object proxy, @Nullable Object target, Method metho
740740
methodProxy : null);
741741
}
742742

743+
@Override
744+
@Nullable
745+
public Object proceed() throws Throwable {
746+
try {
747+
return super.proceed();
748+
}
749+
catch (RuntimeException ex) {
750+
throw ex;
751+
}
752+
catch (Exception ex) {
753+
if (ReflectionUtils.declaresException(getMethod(), ex.getClass())) {
754+
throw ex;
755+
}
756+
else {
757+
throw new UndeclaredThrowableException(ex);
758+
}
759+
}
760+
}
761+
743762
/**
744763
* Gives a marginal performance improvement versus using reflection to
745764
* invoke the target when invoking public methods.
@@ -968,52 +987,4 @@ public int hashCode() {
968987
}
969988
}
970989

971-
972-
/**
973-
* CGLIB GeneratorStrategy variant which exposes the application ClassLoader
974-
* as thread context ClassLoader for the time of class generation
975-
* (in order for ASM to pick it up when doing common superclass resolution).
976-
*/
977-
private static class ClassLoaderAwareUndeclaredThrowableStrategy extends UndeclaredThrowableStrategy {
978-
979-
@Nullable
980-
private final ClassLoader classLoader;
981-
982-
public ClassLoaderAwareUndeclaredThrowableStrategy(@Nullable ClassLoader classLoader) {
983-
super(UndeclaredThrowableException.class);
984-
this.classLoader = classLoader;
985-
}
986-
987-
@Override
988-
public byte[] generate(ClassGenerator cg) throws Exception {
989-
if (this.classLoader == null) {
990-
return super.generate(cg);
991-
}
992-
993-
Thread currentThread = Thread.currentThread();
994-
ClassLoader threadContextClassLoader;
995-
try {
996-
threadContextClassLoader = currentThread.getContextClassLoader();
997-
}
998-
catch (Throwable ex) {
999-
// Cannot access thread context ClassLoader - falling back...
1000-
return super.generate(cg);
1001-
}
1002-
1003-
boolean overrideClassLoader = !this.classLoader.equals(threadContextClassLoader);
1004-
if (overrideClassLoader) {
1005-
currentThread.setContextClassLoader(this.classLoader);
1006-
}
1007-
try {
1008-
return super.generate(cg);
1009-
}
1010-
finally {
1011-
if (overrideClassLoader) {
1012-
// Reset original thread context ClassLoader.
1013-
currentThread.setContextClassLoader(threadContextClassLoader);
1014-
}
1015-
}
1016-
}
1017-
}
1018-
1019990
}

spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -68,7 +68,7 @@ public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Clonea
6868

6969
protected final Method method;
7070

71-
protected Object[] arguments = new Object[0];
71+
protected Object[] arguments;
7272

7373
@Nullable
7474
private final Class<?> targetClass;
@@ -158,7 +158,7 @@ public void setArguments(Object... arguments) {
158158
@Override
159159
@Nullable
160160
public Object proceed() throws Throwable {
161-
// We start with an index of -1 and increment early.
161+
// We start with an index of -1 and increment early.
162162
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
163163
return invokeJoinpoint();
164164
}

spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java

+1-49
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,7 @@
2626
import org.springframework.beans.BeanUtils;
2727
import org.springframework.beans.factory.BeanFactory;
2828
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
29-
import org.springframework.cglib.core.ClassGenerator;
30-
import org.springframework.cglib.core.DefaultGeneratorStrategy;
29+
import org.springframework.cglib.core.ClassLoaderAwareGeneratorStrategy;
3130
import org.springframework.cglib.core.SpringNamingPolicy;
3231
import org.springframework.cglib.proxy.Callback;
3332
import org.springframework.cglib.proxy.CallbackFilter;
@@ -187,53 +186,6 @@ public int hashCode() {
187186
}
188187

189188

190-
/**
191-
* CGLIB GeneratorStrategy variant which exposes the application ClassLoader
192-
* as thread context ClassLoader for the time of class generation
193-
* (in order for ASM to pick it up when doing common superclass resolution).
194-
*/
195-
private static class ClassLoaderAwareGeneratorStrategy extends DefaultGeneratorStrategy {
196-
197-
@Nullable
198-
private final ClassLoader classLoader;
199-
200-
public ClassLoaderAwareGeneratorStrategy(@Nullable ClassLoader classLoader) {
201-
this.classLoader = classLoader;
202-
}
203-
204-
@Override
205-
public byte[] generate(ClassGenerator cg) throws Exception {
206-
if (this.classLoader == null) {
207-
return super.generate(cg);
208-
}
209-
210-
Thread currentThread = Thread.currentThread();
211-
ClassLoader threadContextClassLoader;
212-
try {
213-
threadContextClassLoader = currentThread.getContextClassLoader();
214-
}
215-
catch (Throwable ex) {
216-
// Cannot access thread context ClassLoader - falling back...
217-
return super.generate(cg);
218-
}
219-
220-
boolean overrideClassLoader = !this.classLoader.equals(threadContextClassLoader);
221-
if (overrideClassLoader) {
222-
currentThread.setContextClassLoader(this.classLoader);
223-
}
224-
try {
225-
return super.generate(cg);
226-
}
227-
finally {
228-
if (overrideClassLoader) {
229-
// Reset original thread context ClassLoader.
230-
currentThread.setContextClassLoader(threadContextClassLoader);
231-
}
232-
}
233-
}
234-
}
235-
236-
237189
/**
238190
* CGLIB callback for filtering method interception behavior.
239191
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2002-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cglib.core;
18+
19+
/**
20+
* CGLIB GeneratorStrategy variant which exposes the application ClassLoader
21+
* as current thread context ClassLoader for the time of class generation.
22+
* The ASM ClassWriter in Spring's ASM variant will pick it up when doing
23+
* common superclass resolution.
24+
*
25+
* @author Juergen Hoeller
26+
* @since 5.2
27+
*/
28+
public class ClassLoaderAwareGeneratorStrategy extends DefaultGeneratorStrategy {
29+
30+
private final ClassLoader classLoader;
31+
32+
public ClassLoaderAwareGeneratorStrategy(ClassLoader classLoader) {
33+
this.classLoader = classLoader;
34+
}
35+
36+
@Override
37+
public byte[] generate(ClassGenerator cg) throws Exception {
38+
if (this.classLoader == null) {
39+
return super.generate(cg);
40+
}
41+
42+
Thread currentThread = Thread.currentThread();
43+
ClassLoader threadContextClassLoader;
44+
try {
45+
threadContextClassLoader = currentThread.getContextClassLoader();
46+
}
47+
catch (Throwable ex) {
48+
// Cannot access thread context ClassLoader - falling back...
49+
return super.generate(cg);
50+
}
51+
52+
boolean overrideClassLoader = !this.classLoader.equals(threadContextClassLoader);
53+
if (overrideClassLoader) {
54+
currentThread.setContextClassLoader(this.classLoader);
55+
}
56+
try {
57+
return super.generate(cg);
58+
}
59+
finally {
60+
if (overrideClassLoader) {
61+
// Reset original thread context ClassLoader.
62+
currentThread.setContextClassLoader(threadContextClassLoader);
63+
}
64+
}
65+
}
66+
67+
}

spring-core/src/main/java/org/springframework/cglib/package-info.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* Spring's repackaging of
3-
* <a href="https://github.com/cglib/cglib">CGLIB 3.2</a>
3+
* <a href="https://github.com/cglib/cglib">CGLIB 3.3</a>
44
* (with Spring-specific patches; for internal use only).
55
*
66
* <p>This repackaging technique avoids any potential conflicts with

0 commit comments

Comments
 (0)