001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.test.util; 018 019import org.springframework.aop.framework.Advised; 020import org.springframework.aop.support.AopUtils; 021import org.springframework.util.Assert; 022 023/** 024 * {@code AopTestUtils} is a collection of AOP-related utility methods for 025 * use in unit and integration testing scenarios. 026 * 027 * <p>For Spring's core AOP utilities, see 028 * {@link org.springframework.aop.support.AopUtils AopUtils} and 029 * {@link org.springframework.aop.framework.AopProxyUtils AopProxyUtils}. 030 * 031 * @author Sam Brannen 032 * @author Juergen Hoeller 033 * @since 4.2 034 * @see org.springframework.aop.support.AopUtils 035 * @see org.springframework.aop.framework.AopProxyUtils 036 * @see ReflectionTestUtils 037 */ 038public abstract class AopTestUtils { 039 040 /** 041 * Get the <em>target</em> object of the supplied {@code candidate} object. 042 * <p>If the supplied {@code candidate} is a Spring 043 * {@linkplain AopUtils#isAopProxy proxy}, the target of the proxy will 044 * be returned; otherwise, the {@code candidate} will be returned 045 * <em>as is</em>. 046 * @param candidate the instance to check (potentially a Spring AOP proxy; 047 * never {@code null}) 048 * @return the target object or the {@code candidate} (never {@code null}) 049 * @throws IllegalStateException if an error occurs while unwrapping a proxy 050 * @see Advised#getTargetSource() 051 * @see #getUltimateTargetObject 052 */ 053 @SuppressWarnings("unchecked") 054 public static <T> T getTargetObject(Object candidate) { 055 Assert.notNull(candidate, "Candidate must not be null"); 056 try { 057 if (AopUtils.isAopProxy(candidate) && candidate instanceof Advised) { 058 Object target = ((Advised) candidate).getTargetSource().getTarget(); 059 if (target != null) { 060 return (T) target; 061 } 062 } 063 } 064 catch (Throwable ex) { 065 throw new IllegalStateException("Failed to unwrap proxied object", ex); 066 } 067 return (T) candidate; 068 } 069 070 /** 071 * Get the ultimate <em>target</em> object of the supplied {@code candidate} 072 * object, unwrapping not only a top-level proxy but also any number of 073 * nested proxies. 074 * <p>If the supplied {@code candidate} is a Spring 075 * {@linkplain AopUtils#isAopProxy proxy}, the ultimate target of all 076 * nested proxies will be returned; otherwise, the {@code candidate} 077 * will be returned <em>as is</em>. 078 * @param candidate the instance to check (potentially a Spring AOP proxy; 079 * never {@code null}) 080 * @return the target object or the {@code candidate} (never {@code null}) 081 * @throws IllegalStateException if an error occurs while unwrapping a proxy 082 * @see Advised#getTargetSource() 083 * @see org.springframework.aop.framework.AopProxyUtils#ultimateTargetClass 084 */ 085 @SuppressWarnings("unchecked") 086 public static <T> T getUltimateTargetObject(Object candidate) { 087 Assert.notNull(candidate, "Candidate must not be null"); 088 try { 089 if (AopUtils.isAopProxy(candidate) && candidate instanceof Advised) { 090 Object target = ((Advised) candidate).getTargetSource().getTarget(); 091 if (target != null) { 092 return (T) getUltimateTargetObject(target); 093 } 094 } 095 } 096 catch (Throwable ex) { 097 throw new IllegalStateException("Failed to unwrap proxied object", ex); 098 } 099 return (T) candidate; 100 } 101 102}