From 0a5aff1b60f3082d07c523198e9f9d35aea6ffa3 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 12 Jun 2023 10:48:57 +0200 Subject: [PATCH] Specific check for parent of spring-aop ClassLoader Also applied to getProxyClass now. Closes gh-30389 --- .../aop/framework/JdkDynamicAopProxy.java | 35 +++++++++++++++---- .../aop/framework/ProxyFactoryTests.java | 12 +++++-- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java b/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java index 6d557b62b30..e5f9c08531d 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/JdkDynamicAopProxy.java @@ -120,18 +120,39 @@ final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializa if (logger.isTraceEnabled()) { logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource()); } - if (classLoader == null || classLoader.getParent() == null) { - // JDK bootstrap loader or platform loader suggested -> - // use higher-level loader which can see Spring infrastructure classes - classLoader = getClass().getClassLoader(); - } - return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this); + return Proxy.newProxyInstance(determineClassLoader(classLoader), this.proxiedInterfaces, this); } @SuppressWarnings("deprecation") @Override public Class getProxyClass(@Nullable ClassLoader classLoader) { - return Proxy.getProxyClass(classLoader, this.proxiedInterfaces); + return Proxy.getProxyClass(determineClassLoader(classLoader), this.proxiedInterfaces); + } + + /** + * Determine whether the JDK bootstrap or platform loader has been suggested -> + * use higher-level loader which can see Spring infrastructure classes instead. + */ + private ClassLoader determineClassLoader(@Nullable ClassLoader classLoader) { + if (classLoader == null) { + // JDK bootstrap loader -> use spring-aop ClassLoader instead. + return getClass().getClassLoader(); + } + if (classLoader.getParent() == null) { + // Potentially the JDK platform loader on JDK 9+ + ClassLoader aopClassLoader = getClass().getClassLoader(); + ClassLoader aopParent = aopClassLoader.getParent(); + while (aopParent != null) { + if (classLoader == aopParent) { + // Suggested ClassLoader is ancestor of spring-aop ClassLoader + // -> use spring-aop ClassLoader itself instead. + return aopClassLoader; + } + aopParent = aopParent.getParent(); + } + } + // Regular case: use suggested ClassLoader as-is. + return classLoader; } /** diff --git a/spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java b/spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java index effbed9f8d9..a0f52916504 100644 --- a/spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java +++ b/spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java @@ -389,7 +389,9 @@ public class ProxyFactoryTests { CharSequence target = "test"; ProxyFactory pf = new ProxyFactory(target); ClassLoader cl = target.getClass().getClassLoader(); - assertThat(((CharSequence) pf.getProxy(cl)).toString()).isEqualTo(target); + CharSequence proxy = (CharSequence) pf.getProxy(cl); + assertThat(proxy.toString()).isEqualTo(target); + assertThat(pf.getProxyClass(cl)).isSameAs(proxy.getClass()); } @Test @@ -398,7 +400,9 @@ public class ProxyFactoryTests { ProxyFactory pf = new ProxyFactory(target); pf.setProxyTargetClass(true); ClassLoader cl = target.getClass().getClassLoader(); - assertThat(((Date) pf.getProxy(cl)).getTime()).isEqualTo(target.getTime()); + Date proxy = (Date) pf.getProxy(cl); + assertThat(proxy.getTime()).isEqualTo(target.getTime()); + assertThat(pf.getProxyClass(cl)).isSameAs(proxy.getClass()); } @Test @@ -415,7 +419,9 @@ public class ProxyFactoryTests { }; ProxyFactory pf = new ProxyFactory(target); ClassLoader cl = Savepoint.class.getClassLoader(); - assertThat(((Savepoint) pf.getProxy(cl)).getSavepointName()).isEqualTo("sp"); + Savepoint proxy = (Savepoint) pf.getProxy(cl); + assertThat(proxy.getSavepointName()).isEqualTo("sp"); + assertThat(pf.getProxyClass(cl)).isSameAs(proxy.getClass()); }