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 * @since 4.2
033 * @see org.springframework.aop.support.AopUtils
034 * @see org.springframework.aop.framework.AopProxyUtils
035 * @see ReflectionTestUtils
036 */
037public abstract class AopTestUtils {
038
039        /**
040         * Get the <em>target</em> object of the supplied {@code candidate} object.
041         * <p>If the supplied {@code candidate} is a Spring
042         * {@linkplain AopUtils#isAopProxy proxy}, the target of the proxy will
043         * be returned; otherwise, the {@code candidate} will be returned
044         * <em>as is</em>.
045         * @param candidate the instance to check (potentially a Spring AOP proxy;
046         * never {@code null})
047         * @return the target object or the {@code candidate} (never {@code null})
048         * @throws IllegalStateException if an error occurs while unwrapping a proxy
049         * @see Advised#getTargetSource()
050         * @see #getUltimateTargetObject
051         */
052        @SuppressWarnings("unchecked")
053        public static <T> T getTargetObject(Object candidate) {
054                Assert.notNull(candidate, "Candidate must not be null");
055                try {
056                        if (AopUtils.isAopProxy(candidate) && candidate instanceof Advised) {
057                                return (T) ((Advised) candidate).getTargetSource().getTarget();
058                        }
059                }
060                catch (Throwable ex) {
061                        throw new IllegalStateException("Failed to unwrap proxied object", ex);
062                }
063                return (T) candidate;
064        }
065
066        /**
067         * Get the ultimate <em>target</em> object of the supplied {@code candidate}
068         * object, unwrapping not only a top-level proxy but also any number of
069         * nested proxies.
070         * <p>If the supplied {@code candidate} is a Spring
071         * {@linkplain AopUtils#isAopProxy proxy}, the ultimate target of all
072         * nested proxies will be returned; otherwise, the {@code candidate}
073         * will be returned <em>as is</em>.
074         * @param candidate the instance to check (potentially a Spring AOP proxy;
075         * never {@code null})
076         * @return the target object or the {@code candidate} (never {@code null})
077         * @throws IllegalStateException if an error occurs while unwrapping a proxy
078         * @see Advised#getTargetSource()
079         * @see org.springframework.aop.framework.AopProxyUtils#ultimateTargetClass
080         */
081        @SuppressWarnings("unchecked")
082        public static <T> T getUltimateTargetObject(Object candidate) {
083                Assert.notNull(candidate, "Candidate must not be null");
084                try {
085                        if (AopUtils.isAopProxy(candidate) && candidate instanceof Advised) {
086                                return (T) getUltimateTargetObject(((Advised) candidate).getTargetSource().getTarget());
087                        }
088                }
089                catch (Throwable ex) {
090                        throw new IllegalStateException("Failed to unwrap proxied object", ex);
091                }
092                return (T) candidate;
093        }
094
095}