diff --git a/org.springframework.aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java b/org.springframework.aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java
index 54e73e13a1..5325014382 100644
--- a/org.springframework.aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java
+++ b/org.springframework.aop/src/main/java/org/springframework/aop/framework/AopProxyUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2008 the original author or authors.
+ * Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,9 @@ package org.springframework.aop.framework;
import java.util.Arrays;
import org.springframework.aop.SpringProxy;
+import org.springframework.aop.TargetClassAware;
+import org.springframework.aop.TargetSource;
+import org.springframework.aop.target.SingletonTargetSource;
import org.springframework.util.Assert;
/**
@@ -34,6 +37,34 @@ import org.springframework.util.Assert;
*/
public abstract class AopProxyUtils {
+ /**
+ * Determine the ultimate target class of the given bean instance, traversing
+ * not only a top-level proxy but any number of nested proxies as well -
+ * as long as possible without side effects, that is, just for singleton targets.
+ * @param candidate the instance to check (might be an AOP proxy)
+ * @return the target class (or the plain class of the given object as fallback;
+ * never null)
+ * @see org.springframework.aop.TargetClassAware#getTargetClass()
+ * @see org.springframework.aop.framework.Advised#getTargetSource()
+ */
+ public static Class> ultimateTargetClass(Object candidate) {
+ Assert.notNull(candidate, "Candidate object must not be null");
+ Object current = candidate;
+ Class> result = null;
+ while (current instanceof TargetClassAware) {
+ result = ((TargetClassAware) current).getTargetClass();
+ Object nested = null;
+ if (current instanceof Advised) {
+ TargetSource targetSource = ((Advised) current).getTargetSource();
+ if (targetSource instanceof SingletonTargetSource) {
+ nested = ((SingletonTargetSource) targetSource).getTarget();
+ }
+ }
+ current = nested;
+ }
+ return result;
+ }
+
/**
* Determine the complete set of interfaces to proxy for the given AOP configuration.
*
This will always add the {@link Advised} interface unless the AdvisedSupport's diff --git a/org.springframework.aop/src/main/java/org/springframework/aop/support/AopUtils.java b/org.springframework.aop/src/main/java/org/springframework/aop/support/AopUtils.java index 2dc9d58bb9..972f96d166 100644 --- a/org.springframework.aop/src/main/java/org/springframework/aop/support/AopUtils.java +++ b/org.springframework.aop/src/main/java/org/springframework/aop/support/AopUtils.java @@ -98,13 +98,13 @@ public abstract class AopUtils { } /** - * Determine the target class of the given bean instance, - * which might be an AOP proxy. + * Determine the target class of the given bean instance which might be an AOP proxy. *
Returns the target class for an AOP proxy and the plain class else.
* @param candidate the instance to check (might be an AOP proxy)
* @return the target class (or the plain class of the given object as fallback;
* never null)
* @see org.springframework.aop.TargetClassAware#getTargetClass()
+ * @see org.springframework.aop.framework.AopProxyUtils#ultimateTargetClass(Object)
*/
public static Class> getTargetClass(Object candidate) {
Assert.notNull(candidate, "Candidate object must not be null");
diff --git a/org.springframework.aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java b/org.springframework.aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java
index b01f5d7779..f7d325e4c5 100644
--- a/org.springframework.aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java
+++ b/org.springframework.aop/src/test/java/org/springframework/aop/framework/ProxyFactoryTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -293,20 +293,33 @@ public final class ProxyFactoryTests {
public void testProxyTargetClassWithInterfaceAsTarget() {
ProxyFactory pf = new ProxyFactory();
pf.setTargetClass(ITestBean.class);
-
Object proxy = pf.getProxy();
assertTrue("Proxy is a JDK proxy", AopUtils.isJdkDynamicProxy(proxy));
assertTrue(proxy instanceof ITestBean);
+ assertEquals(ITestBean.class, AopProxyUtils.ultimateTargetClass(proxy));
+
+ ProxyFactory pf2 = new ProxyFactory(proxy);
+ Object proxy2 = pf2.getProxy();
+ assertTrue("Proxy is a JDK proxy", AopUtils.isJdkDynamicProxy(proxy2));
+ assertTrue(proxy2 instanceof ITestBean);
+ assertEquals(ITestBean.class, AopProxyUtils.ultimateTargetClass(proxy2));
}
@Test
public void testProxyTargetClassWithConcreteClassAsTarget() {
ProxyFactory pf = new ProxyFactory();
pf.setTargetClass(TestBean.class);
-
Object proxy = pf.getProxy();
assertTrue("Proxy is a CGLIB proxy", AopUtils.isCglibProxy(proxy));
assertTrue(proxy instanceof TestBean);
+ assertEquals(TestBean.class, AopProxyUtils.ultimateTargetClass(proxy));
+
+ ProxyFactory pf2 = new ProxyFactory(proxy);
+ pf2.setProxyTargetClass(true);
+ Object proxy2 = pf2.getProxy();
+ assertTrue("Proxy is a CGLIB proxy", AopUtils.isCglibProxy(proxy2));
+ assertTrue(proxy2 instanceof TestBean);
+ assertEquals(TestBean.class, AopProxyUtils.ultimateTargetClass(proxy2));
}
@Test