diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java b/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java index 282d0584be38..009ff490f964 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java @@ -34,6 +34,7 @@ import org.springframework.aop.IntroductionInfo; import org.springframework.aop.Pointcut; import org.springframework.aop.PointcutAdvisor; +import org.springframework.aop.SpringProxy; import org.springframework.aop.TargetSource; import org.springframework.aop.support.DefaultIntroductionAdvisor; import org.springframework.aop.support.DefaultPointcutAdvisor; @@ -222,15 +223,15 @@ public void setInterfaces(Class... interfaces) { /** * Add a new proxied interface. - * @param intf the additional interface to proxy + * @param ifc the additional interface to proxy */ - public void addInterface(Class intf) { - Assert.notNull(intf, "Interface must not be null"); - if (!intf.isInterface()) { - throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface"); + public void addInterface(Class ifc) { + Assert.notNull(ifc, "Interface must not be null"); + if (!ifc.isInterface()) { + throw new IllegalArgumentException("[" + ifc.getName() + "] is not an interface"); } - if (!this.interfaces.contains(intf)) { - this.interfaces.add(intf); + if (!this.interfaces.contains(ifc)) { + this.interfaces.add(ifc); adviceChanged(); } } @@ -238,12 +239,12 @@ public void addInterface(Class intf) { /** * Remove a proxied interface. *

Does nothing if the given interface isn't proxied. - * @param intf the interface to remove from the proxy + * @param ifc the interface to remove from the proxy * @return {@code true} if the interface was removed; {@code false} * if the interface was not found and hence could not be removed */ - public boolean removeInterface(Class intf) { - return this.interfaces.remove(intf); + public boolean removeInterface(Class ifc) { + return this.interfaces.remove(ifc); } @Override @@ -252,15 +253,37 @@ public Class[] getProxiedInterfaces() { } @Override - public boolean isInterfaceProxied(Class intf) { + public boolean isInterfaceProxied(Class ifc) { for (Class proxyIntf : this.interfaces) { - if (intf.isAssignableFrom(proxyIntf)) { + if (ifc.isAssignableFrom(proxyIntf)) { return true; } } return false; } + boolean hasUserSuppliedInterfaces() { + for (Class ifc : this.interfaces) { + if (!SpringProxy.class.isAssignableFrom(ifc) && !isAdvisorIntroducedInterface(ifc)) { + return true; + } + } + return false; + } + + private boolean isAdvisorIntroducedInterface(Class ifc) { + for (Advisor advisor : this.advisors) { + if (advisor instanceof IntroductionAdvisor introductionAdvisor) { + for (Class introducedInterface : introductionAdvisor.getInterfaces()) { + if (introducedInterface == ifc) { + return true; + } + } + } + } + return false; + } + @Override public final Advisor[] getAdvisors() { diff --git a/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java b/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java index 1f0977963f8f..151ef1455b2c 100644 --- a/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java +++ b/spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java @@ -19,7 +19,6 @@ import java.io.Serializable; import java.lang.reflect.Proxy; -import org.springframework.aop.SpringProxy; import org.springframework.util.ClassUtils; /** @@ -59,7 +58,7 @@ public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { @Override public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { - if (config.isOptimize() || config.isProxyTargetClass() || !hasTargetInterfaces(config)) { + if (config.isOptimize() || config.isProxyTargetClass() || !config.hasUserSuppliedInterfaces()) { Class targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + @@ -75,14 +74,4 @@ public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException } } - private boolean hasTargetInterfaces(AdvisedSupport config) { - Class targetClass = config.getTargetClass(); - for (Class ifc : config.getProxiedInterfaces()) { - if (targetClass != null ? ifc.isAssignableFrom(targetClass) : !SpringProxy.class.isAssignableFrom(ifc)) { - return true; - } - } - return false; - } - } 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 28e8b7ee6f54..76b736830cf0 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 @@ -199,7 +199,7 @@ public int compareTo(Object arg0) { Class[] oldProxiedInterfaces = pf.getProxiedInterfaces(); long t = 555555L; TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(t); - pf.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class)); + pf.addAdvisor(new DefaultIntroductionAdvisor(ti, TimeStamped.class)); Class[] newProxiedInterfaces = pf.getProxiedInterfaces(); assertThat(newProxiedInterfaces).as("Advisor proxies one more interface after introduction").hasSize(oldProxiedInterfaces.length + 1); @@ -328,11 +328,11 @@ void proxyTargetClassWithConcreteClassAsTarget() { } @Test - void proxyTargetClassWithIntroducedInterface() { + void proxyTargetClassInCaseOfIntroducedInterface() { ProxyFactory pf = new ProxyFactory(); pf.setTargetClass(MyDate.class); TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(0L); - pf.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class)); + pf.addAdvisor(new DefaultIntroductionAdvisor(ti, TimeStamped.class)); Object proxy = pf.getProxy(); assertThat(AopUtils.isCglibProxy(proxy)).as("Proxy is a CGLIB proxy").isTrue(); assertThat(proxy).isInstanceOf(MyDate.class); @@ -340,6 +340,20 @@ void proxyTargetClassWithIntroducedInterface() { assertThat(AopProxyUtils.ultimateTargetClass(proxy)).isEqualTo(MyDate.class); } + @Test + void proxyInterfaceInCaseOfNonTargetInterface() { + ProxyFactory pf = new ProxyFactory(); + pf.setTargetClass(MyDate.class); + pf.addInterface(TimeStamped.class); + pf.addAdvice((MethodInterceptor) invocation -> { + throw new UnsupportedOperationException(); + }); + Object proxy = pf.getProxy(); + assertThat(AopUtils.isJdkDynamicProxy(proxy)).as("Proxy is a JDK proxy").isTrue(); + assertThat(proxy).isInstanceOf(TimeStamped.class); + assertThat(AopProxyUtils.ultimateTargetClass(proxy)).isEqualTo(MyDate.class); + } + @Test void interfaceProxiesCanBeOrderedThroughAnnotations() { Object proxy1 = new ProxyFactory(new A()).getProxy();