001/*
002 * Copyright 2002-2015 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.aop.framework.autoproxy;
018
019import org.springframework.beans.factory.config.BeanDefinition;
020import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
021import org.springframework.core.Conventions;
022
023/**
024 * Utilities for auto-proxy aware components.
025 * Mainly for internal use within the framework.
026 *
027 * @author Juergen Hoeller
028 * @since 2.0.3
029 * @see AbstractAutoProxyCreator
030 */
031public abstract class AutoProxyUtils {
032
033        /**
034         * Bean definition attribute that may indicate whether a given bean is supposed
035         * to be proxied with its target class (in case of it getting proxied in the first
036         * place). The value is {@code Boolean.TRUE} or {@code Boolean.FALSE}.
037         * <p>Proxy factories can set this attribute if they built a target class proxy
038         * for a specific bean, and want to enforce that bean can always be cast
039         * to its target class (even if AOP advices get applied through auto-proxying).
040         * @see #shouldProxyTargetClass
041         */
042        public static final String PRESERVE_TARGET_CLASS_ATTRIBUTE =
043                        Conventions.getQualifiedAttributeName(AutoProxyUtils.class, "preserveTargetClass");
044
045        /**
046         * Bean definition attribute that indicates the original target class of an
047         * auto-proxied bean, e.g. to be used for the introspection of annotations
048         * on the target class behind an interface-based proxy.
049         * @since 4.2.3
050         * @see #determineTargetClass
051         */
052        public static final String ORIGINAL_TARGET_CLASS_ATTRIBUTE =
053                        Conventions.getQualifiedAttributeName(AutoProxyUtils.class, "originalTargetClass");
054
055
056        /**
057         * Determine whether the given bean should be proxied with its target
058         * class rather than its interfaces. Checks the
059         * {@link #PRESERVE_TARGET_CLASS_ATTRIBUTE "preserveTargetClass" attribute}
060         * of the corresponding bean definition.
061         * @param beanFactory the containing ConfigurableListableBeanFactory
062         * @param beanName the name of the bean
063         * @return whether the given bean should be proxied with its target class
064         */
065        public static boolean shouldProxyTargetClass(ConfigurableListableBeanFactory beanFactory, String beanName) {
066                if (beanName != null && beanFactory.containsBeanDefinition(beanName)) {
067                        BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
068                        return Boolean.TRUE.equals(bd.getAttribute(PRESERVE_TARGET_CLASS_ATTRIBUTE));
069                }
070                return false;
071        }
072
073        /**
074         * Determine the original target class for the specified bean, if possible,
075         * otherwise falling back to a regular {@code getType} lookup.
076         * @param beanFactory the containing ConfigurableListableBeanFactory
077         * @param beanName the name of the bean
078         * @return the original target class as stored in the bean definition, if any
079         * @since 4.2.3
080         * @see org.springframework.beans.factory.BeanFactory#getType(String)
081         */
082        public static Class<?> determineTargetClass(ConfigurableListableBeanFactory beanFactory, String beanName) {
083                if (beanName == null) {
084                        return null;
085                }
086                if (beanFactory.containsBeanDefinition(beanName)) {
087                        BeanDefinition bd = beanFactory.getMergedBeanDefinition(beanName);
088                        Class<?> targetClass = (Class<?>) bd.getAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE);
089                        if (targetClass != null) {
090                                return targetClass;
091                        }
092                }
093                return beanFactory.getType(beanName);
094        }
095
096        /**
097         * Expose the given target class for the specified bean, if possible.
098         * @param beanFactory the containing ConfigurableListableBeanFactory
099         * @param beanName the name of the bean
100         * @param targetClass the corresponding target class
101         * @since 4.2.3
102         */
103        static void exposeTargetClass(ConfigurableListableBeanFactory beanFactory, String beanName, Class<?> targetClass) {
104                if (beanName != null && beanFactory.containsBeanDefinition(beanName)) {
105                        beanFactory.getMergedBeanDefinition(beanName).setAttribute(ORIGINAL_TARGET_CLASS_ATTRIBUTE, targetClass);
106                }
107        }
108
109}