From 9bd3a535cd524cf771423e67feeea523ac985f87 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 14 Aug 2019 00:14:14 +0200 Subject: [PATCH] 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 --- .../aop/framework/CglibAopProxy.java | 77 ++++++------------- .../framework/ReflectiveMethodInvocation.java | 6 +- ...CglibSubclassingInstantiationStrategy.java | 50 +----------- .../ClassLoaderAwareGeneratorStrategy.java | 67 ++++++++++++++++ .../springframework/cglib/package-info.java | 2 +- 5 files changed, 96 insertions(+), 106 deletions(-) create mode 100644 spring-core/src/main/java/org/springframework/cglib/core/ClassLoaderAwareGeneratorStrategy.java diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java index a578b29f54..1e899671aa 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/CglibAopProxy.java @@ -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); - } - } - } - } - } diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java b/spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java index e365bd2bba..0eef701a93 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/ReflectiveMethodInvocation.java @@ -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(); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java index 59ee973917..a81a523404 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/CglibSubclassingInstantiationStrategy.java @@ -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. */ diff --git a/spring-core/src/main/java/org/springframework/cglib/core/ClassLoaderAwareGeneratorStrategy.java b/spring-core/src/main/java/org/springframework/cglib/core/ClassLoaderAwareGeneratorStrategy.java new file mode 100644 index 0000000000..eb746444fc --- /dev/null +++ b/spring-core/src/main/java/org/springframework/cglib/core/ClassLoaderAwareGeneratorStrategy.java @@ -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); + } + } + } + +} diff --git a/spring-core/src/main/java/org/springframework/cglib/package-info.java b/spring-core/src/main/java/org/springframework/cglib/package-info.java index ee1e30ea86..638ce59770 100644 --- a/spring-core/src/main/java/org/springframework/cglib/package-info.java +++ b/spring-core/src/main/java/org/springframework/cglib/package-info.java @@ -1,6 +1,6 @@ /** * Spring's repackaging of - * CGLIB 3.2 + * CGLIB 3.3 * (with Spring-specific patches; for internal use only). * *

This repackaging technique avoids any potential conflicts with