Skip to content

Commit

Permalink
Check for advisor-introduced interfaces specifically
Browse files Browse the repository at this point in the history
  • Loading branch information
jhoeller committed Sep 27, 2024
1 parent d3dd01e commit 8680c43
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -222,28 +223,28 @@ 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();
}
}

/**
* Remove a proxied interface.
* <p>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
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.io.Serializable;
import java.lang.reflect.Proxy;

import org.springframework.aop.SpringProxy;
import org.springframework.util.ClassUtils;

/**
Expand Down Expand Up @@ -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: " +
Expand All @@ -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;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -328,18 +328,32 @@ 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);
assertThat(proxy).isInstanceOf(TimeStamped.class);
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();
Expand Down

0 comments on commit 8680c43

Please sign in to comment.