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}