From 87e327773ee7be8fca0c0a5f5724b42de5c512dd Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 22 Apr 2010 21:36:53 +0000 Subject: [PATCH] introduced AopProxyUtils.ultimateTargetClass (SPR-7074) --- .../aop/framework/AopProxyUtils.java | 33 ++++++++++++++++++- .../springframework/aop/support/AopUtils.java | 4 +-- .../aop/framework/ProxyFactoryTests.java | 19 +++++++++-- 3 files changed, 50 insertions(+), 6 deletions(-) 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 54e73e13a12..5325014382b 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 2dc9d58bb90..972f96d166d 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 b01f5d7779e..f7d325e4c53 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