Skip to content

Commit 8680c43

Browse files
committed
Check for advisor-introduced interfaces specifically
See gh-31304
1 parent d3dd01e commit 8680c43

File tree

3 files changed

+53
-27
lines changed

3 files changed

+53
-27
lines changed

Diff for: spring-aop/src/main/java/org/springframework/aop/framework/AdvisedSupport.java

+35-12
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.aop.IntroductionInfo;
3535
import org.springframework.aop.Pointcut;
3636
import org.springframework.aop.PointcutAdvisor;
37+
import org.springframework.aop.SpringProxy;
3738
import org.springframework.aop.TargetSource;
3839
import org.springframework.aop.support.DefaultIntroductionAdvisor;
3940
import org.springframework.aop.support.DefaultPointcutAdvisor;
@@ -222,28 +223,28 @@ public void setInterfaces(Class<?>... interfaces) {
222223

223224
/**
224225
* Add a new proxied interface.
225-
* @param intf the additional interface to proxy
226+
* @param ifc the additional interface to proxy
226227
*/
227-
public void addInterface(Class<?> intf) {
228-
Assert.notNull(intf, "Interface must not be null");
229-
if (!intf.isInterface()) {
230-
throw new IllegalArgumentException("[" + intf.getName() + "] is not an interface");
228+
public void addInterface(Class<?> ifc) {
229+
Assert.notNull(ifc, "Interface must not be null");
230+
if (!ifc.isInterface()) {
231+
throw new IllegalArgumentException("[" + ifc.getName() + "] is not an interface");
231232
}
232-
if (!this.interfaces.contains(intf)) {
233-
this.interfaces.add(intf);
233+
if (!this.interfaces.contains(ifc)) {
234+
this.interfaces.add(ifc);
234235
adviceChanged();
235236
}
236237
}
237238

238239
/**
239240
* Remove a proxied interface.
240241
* <p>Does nothing if the given interface isn't proxied.
241-
* @param intf the interface to remove from the proxy
242+
* @param ifc the interface to remove from the proxy
242243
* @return {@code true} if the interface was removed; {@code false}
243244
* if the interface was not found and hence could not be removed
244245
*/
245-
public boolean removeInterface(Class<?> intf) {
246-
return this.interfaces.remove(intf);
246+
public boolean removeInterface(Class<?> ifc) {
247+
return this.interfaces.remove(ifc);
247248
}
248249

249250
@Override
@@ -252,15 +253,37 @@ public Class<?>[] getProxiedInterfaces() {
252253
}
253254

254255
@Override
255-
public boolean isInterfaceProxied(Class<?> intf) {
256+
public boolean isInterfaceProxied(Class<?> ifc) {
256257
for (Class<?> proxyIntf : this.interfaces) {
257-
if (intf.isAssignableFrom(proxyIntf)) {
258+
if (ifc.isAssignableFrom(proxyIntf)) {
258259
return true;
259260
}
260261
}
261262
return false;
262263
}
263264

265+
boolean hasUserSuppliedInterfaces() {
266+
for (Class<?> ifc : this.interfaces) {
267+
if (!SpringProxy.class.isAssignableFrom(ifc) && !isAdvisorIntroducedInterface(ifc)) {
268+
return true;
269+
}
270+
}
271+
return false;
272+
}
273+
274+
private boolean isAdvisorIntroducedInterface(Class<?> ifc) {
275+
for (Advisor advisor : this.advisors) {
276+
if (advisor instanceof IntroductionAdvisor introductionAdvisor) {
277+
for (Class<?> introducedInterface : introductionAdvisor.getInterfaces()) {
278+
if (introducedInterface == ifc) {
279+
return true;
280+
}
281+
}
282+
}
283+
}
284+
return false;
285+
}
286+
264287

265288
@Override
266289
public final Advisor[] getAdvisors() {

Diff for: spring-aop/src/main/java/org/springframework/aop/framework/DefaultAopProxyFactory.java

+1-12
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.io.Serializable;
2020
import java.lang.reflect.Proxy;
2121

22-
import org.springframework.aop.SpringProxy;
2322
import org.springframework.util.ClassUtils;
2423

2524
/**
@@ -59,7 +58,7 @@ public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
5958

6059
@Override
6160
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
62-
if (config.isOptimize() || config.isProxyTargetClass() || !hasTargetInterfaces(config)) {
61+
if (config.isOptimize() || config.isProxyTargetClass() || !config.hasUserSuppliedInterfaces()) {
6362
Class<?> targetClass = config.getTargetClass();
6463
if (targetClass == null) {
6564
throw new AopConfigException("TargetSource cannot determine target class: " +
@@ -75,14 +74,4 @@ public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException
7574
}
7675
}
7776

78-
private boolean hasTargetInterfaces(AdvisedSupport config) {
79-
Class<?> targetClass = config.getTargetClass();
80-
for (Class<?> ifc : config.getProxiedInterfaces()) {
81-
if (targetClass != null ? ifc.isAssignableFrom(targetClass) : !SpringProxy.class.isAssignableFrom(ifc)) {
82-
return true;
83-
}
84-
}
85-
return false;
86-
}
87-
8877
}

Diff for: spring-aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java

+17-3
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ public int compareTo(Object arg0) {
199199
Class<?>[] oldProxiedInterfaces = pf.getProxiedInterfaces();
200200
long t = 555555L;
201201
TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(t);
202-
pf.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class));
202+
pf.addAdvisor(new DefaultIntroductionAdvisor(ti, TimeStamped.class));
203203

204204
Class<?>[] newProxiedInterfaces = pf.getProxiedInterfaces();
205205
assertThat(newProxiedInterfaces).as("Advisor proxies one more interface after introduction").hasSize(oldProxiedInterfaces.length + 1);
@@ -328,18 +328,32 @@ void proxyTargetClassWithConcreteClassAsTarget() {
328328
}
329329

330330
@Test
331-
void proxyTargetClassWithIntroducedInterface() {
331+
void proxyTargetClassInCaseOfIntroducedInterface() {
332332
ProxyFactory pf = new ProxyFactory();
333333
pf.setTargetClass(MyDate.class);
334334
TimestampIntroductionInterceptor ti = new TimestampIntroductionInterceptor(0L);
335-
pf.addAdvisor(0, new DefaultIntroductionAdvisor(ti, TimeStamped.class));
335+
pf.addAdvisor(new DefaultIntroductionAdvisor(ti, TimeStamped.class));
336336
Object proxy = pf.getProxy();
337337
assertThat(AopUtils.isCglibProxy(proxy)).as("Proxy is a CGLIB proxy").isTrue();
338338
assertThat(proxy).isInstanceOf(MyDate.class);
339339
assertThat(proxy).isInstanceOf(TimeStamped.class);
340340
assertThat(AopProxyUtils.ultimateTargetClass(proxy)).isEqualTo(MyDate.class);
341341
}
342342

343+
@Test
344+
void proxyInterfaceInCaseOfNonTargetInterface() {
345+
ProxyFactory pf = new ProxyFactory();
346+
pf.setTargetClass(MyDate.class);
347+
pf.addInterface(TimeStamped.class);
348+
pf.addAdvice((MethodInterceptor) invocation -> {
349+
throw new UnsupportedOperationException();
350+
});
351+
Object proxy = pf.getProxy();
352+
assertThat(AopUtils.isJdkDynamicProxy(proxy)).as("Proxy is a JDK proxy").isTrue();
353+
assertThat(proxy).isInstanceOf(TimeStamped.class);
354+
assertThat(AopProxyUtils.ultimateTargetClass(proxy)).isEqualTo(MyDate.class);
355+
}
356+
343357
@Test
344358
void interfaceProxiesCanBeOrderedThroughAnnotations() {
345359
Object proxy1 = new ProxyFactory(new A()).getProxy();

0 commit comments

Comments
 (0)