Skip to content

Commit 87e3277

Browse files
committed
introduced AopProxyUtils.ultimateTargetClass (SPR-7074)
1 parent b28310b commit 87e3277

File tree

3 files changed

+50
-6
lines changed

3 files changed

+50
-6
lines changed

org.springframework.aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2008 the original author or authors.
2+
* Copyright 2002-2010 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.
@@ -19,6 +19,9 @@
1919
import java.util.Arrays;
2020

2121
import org.springframework.aop.SpringProxy;
22+
import org.springframework.aop.TargetClassAware;
23+
import org.springframework.aop.TargetSource;
24+
import org.springframework.aop.target.SingletonTargetSource;
2225
import org.springframework.util.Assert;
2326

2427
/**
@@ -34,6 +37,34 @@
3437
*/
3538
public abstract class AopProxyUtils {
3639

40+
/**
41+
* Determine the ultimate target class of the given bean instance, traversing
42+
* not only a top-level proxy but any number of nested proxies as well -
43+
* as long as possible without side effects, that is, just for singleton targets.
44+
* @param candidate the instance to check (might be an AOP proxy)
45+
* @return the target class (or the plain class of the given object as fallback;
46+
* never <code>null</code>)
47+
* @see org.springframework.aop.TargetClassAware#getTargetClass()
48+
* @see org.springframework.aop.framework.Advised#getTargetSource()
49+
*/
50+
public static Class<?> ultimateTargetClass(Object candidate) {
51+
Assert.notNull(candidate, "Candidate object must not be null");
52+
Object current = candidate;
53+
Class<?> result = null;
54+
while (current instanceof TargetClassAware) {
55+
result = ((TargetClassAware) current).getTargetClass();
56+
Object nested = null;
57+
if (current instanceof Advised) {
58+
TargetSource targetSource = ((Advised) current).getTargetSource();
59+
if (targetSource instanceof SingletonTargetSource) {
60+
nested = ((SingletonTargetSource) targetSource).getTarget();
61+
}
62+
}
63+
current = nested;
64+
}
65+
return result;
66+
}
67+
3768
/**
3869
* Determine the complete set of interfaces to proxy for the given AOP configuration.
3970
* <p>This will always add the {@link Advised} interface unless the AdvisedSupport's

org.springframework.aop/src/main/java/org/springframework/aop/support/AopUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,13 @@ public static boolean isCglibProxyClassName(String className) {
9898
}
9999

100100
/**
101-
* Determine the target class of the given bean instance,
102-
* which might be an AOP proxy.
101+
* Determine the target class of the given bean instance which might be an AOP proxy.
103102
* <p>Returns the target class for an AOP proxy and the plain class else.
104103
* @param candidate the instance to check (might be an AOP proxy)
105104
* @return the target class (or the plain class of the given object as fallback;
106105
* never <code>null</code>)
107106
* @see org.springframework.aop.TargetClassAware#getTargetClass()
107+
* @see org.springframework.aop.framework.AopProxyUtils#ultimateTargetClass(Object)
108108
*/
109109
public static Class<?> getTargetClass(Object candidate) {
110110
Assert.notNull(candidate, "Candidate object must not be null");

org.springframework.aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2009 the original author or authors.
2+
* Copyright 2002-2010 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.
@@ -293,20 +293,33 @@ public void testCanAddAndRemoveAspectInterfacesOnSingleton() {
293293
public void testProxyTargetClassWithInterfaceAsTarget() {
294294
ProxyFactory pf = new ProxyFactory();
295295
pf.setTargetClass(ITestBean.class);
296-
297296
Object proxy = pf.getProxy();
298297
assertTrue("Proxy is a JDK proxy", AopUtils.isJdkDynamicProxy(proxy));
299298
assertTrue(proxy instanceof ITestBean);
299+
assertEquals(ITestBean.class, AopProxyUtils.ultimateTargetClass(proxy));
300+
301+
ProxyFactory pf2 = new ProxyFactory(proxy);
302+
Object proxy2 = pf2.getProxy();
303+
assertTrue("Proxy is a JDK proxy", AopUtils.isJdkDynamicProxy(proxy2));
304+
assertTrue(proxy2 instanceof ITestBean);
305+
assertEquals(ITestBean.class, AopProxyUtils.ultimateTargetClass(proxy2));
300306
}
301307

302308
@Test
303309
public void testProxyTargetClassWithConcreteClassAsTarget() {
304310
ProxyFactory pf = new ProxyFactory();
305311
pf.setTargetClass(TestBean.class);
306-
307312
Object proxy = pf.getProxy();
308313
assertTrue("Proxy is a CGLIB proxy", AopUtils.isCglibProxy(proxy));
309314
assertTrue(proxy instanceof TestBean);
315+
assertEquals(TestBean.class, AopProxyUtils.ultimateTargetClass(proxy));
316+
317+
ProxyFactory pf2 = new ProxyFactory(proxy);
318+
pf2.setProxyTargetClass(true);
319+
Object proxy2 = pf2.getProxy();
320+
assertTrue("Proxy is a CGLIB proxy", AopUtils.isCglibProxy(proxy2));
321+
assertTrue(proxy2 instanceof TestBean);
322+
assertEquals(TestBean.class, AopProxyUtils.ultimateTargetClass(proxy2));
310323
}
311324

312325
@Test

0 commit comments

Comments
 (0)