Skip to content

Commit bdbd999

Browse files
committed
Make proxyTargetClass=true with introduction advice work for JDK proxy targets
Closes gh-27044 (cherry picked from commit c45c46d)
1 parent bc4af15 commit bdbd999

File tree

2 files changed

+33
-6
lines changed

2 files changed

+33
-6
lines changed

spring-aop/src/main/java/org/springframework/aop/framework/autoproxy/AbstractAutoProxyCreator.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.aop.framework.autoproxy;
1818

1919
import java.lang.reflect.Constructor;
20+
import java.lang.reflect.Proxy;
2021
import java.util.ArrayList;
2122
import java.util.Arrays;
2223
import java.util.Collections;
@@ -449,7 +450,17 @@ protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
449450
ProxyFactory proxyFactory = new ProxyFactory();
450451
proxyFactory.copyFrom(this);
451452

452-
if (!proxyFactory.isProxyTargetClass()) {
453+
if (proxyFactory.isProxyTargetClass()) {
454+
// Explicit handling of JDK proxy targets (for introduction advice scenarios)
455+
if (Proxy.isProxyClass(beanClass)) {
456+
// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
457+
for (Class<?> ifc : beanClass.getInterfaces()) {
458+
proxyFactory.addInterface(ifc);
459+
}
460+
}
461+
}
462+
else {
463+
// No proxyTargetClass flag enforced, let's apply our default checks...
453464
if (shouldProxyTargetClass(beanClass, beanName)) {
454465
proxyFactory.setProxyTargetClass(true);
455466
}

spring-context/src/test/java/org/springframework/aop/framework/autoproxy/AutoProxyCreatorTests.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@
2828
import org.springframework.aop.TargetSource;
2929
import org.springframework.aop.framework.ProxyFactory;
3030
import org.springframework.aop.support.AopUtils;
31+
import org.springframework.aop.support.DefaultIntroductionAdvisor;
3132
import org.springframework.aop.target.SingletonTargetSource;
3233
import org.springframework.beans.MutablePropertyValues;
3334
import org.springframework.beans.factory.BeanFactory;
@@ -219,7 +220,7 @@ public void testAutoProxyCreatorWithFallbackToDynamicProxy() {
219220

220221
MutablePropertyValues pvs = new MutablePropertyValues();
221222
pvs.add("proxyFactoryBean", "false");
222-
sac.registerSingleton("testAutoProxyCreator", TestAutoProxyCreator.class, pvs);
223+
sac.registerSingleton("testAutoProxyCreator", IntroductionTestAutoProxyCreator.class, pvs);
223224

224225
sac.registerSingleton("noInterfaces", NoInterfaces.class);
225226
sac.registerSingleton("containerCallbackInterfacesOnly", ContainerCallbackInterfacesOnly.class);
@@ -248,9 +249,9 @@ public void testAutoProxyCreatorWithFallbackToDynamicProxy() {
248249
singletonNoInterceptor.getName();
249250
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(0);
250251
singletonToBeProxied.getAge();
251-
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(1);
252-
prototypeToBeProxied.getSpouse();
253252
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(2);
253+
prototypeToBeProxied.getSpouse();
254+
assertThat(tapc.testInterceptor.nrOfInvocations).isEqualTo(4);
254255
}
255256

256257
@Test
@@ -404,7 +405,7 @@ protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String name,
404405
else if (name.endsWith("ToBeProxied")) {
405406
boolean isFactoryBean = FactoryBean.class.isAssignableFrom(beanClass);
406407
if ((this.proxyFactoryBean && isFactoryBean) || (this.proxyObject && !isFactoryBean)) {
407-
return new Object[] {this.testInterceptor};
408+
return getAdvicesAndAdvisors();
408409
}
409410
else {
410411
return DO_NOT_PROXY;
@@ -414,6 +415,10 @@ else if (name.endsWith("ToBeProxied")) {
414415
return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
415416
}
416417
}
418+
419+
protected Object[] getAdvicesAndAdvisors() {
420+
return new Object[] {this.testInterceptor};
421+
}
417422
}
418423

419424

@@ -426,6 +431,17 @@ public FallbackTestAutoProxyCreator() {
426431
}
427432

428433

434+
@SuppressWarnings("serial")
435+
public static class IntroductionTestAutoProxyCreator extends TestAutoProxyCreator {
436+
437+
protected Object[] getAdvicesAndAdvisors() {
438+
DefaultIntroductionAdvisor advisor = new DefaultIntroductionAdvisor(this.testInterceptor);
439+
advisor.addInterface(Serializable.class);
440+
return new Object[] {this.testInterceptor, advisor};
441+
}
442+
}
443+
444+
429445
/**
430446
* Interceptor that counts the number of non-finalize method calls.
431447
*/

0 commit comments

Comments
 (0)