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.beans.factory.config;
018
019import org.apache.commons.logging.Log;
020import org.apache.commons.logging.LogFactory;
021
022import org.springframework.beans.BeansException;
023import org.springframework.beans.factory.BeanFactory;
024import org.springframework.util.ClassUtils;
025import org.springframework.util.StringUtils;
026
027/**
028 * Bean factory post processor that logs a warning for {@link Deprecated @Deprecated} beans.
029 *
030 * @author Arjen Poutsma
031 * @since 3.0.3
032 */
033public class DeprecatedBeanWarner implements BeanFactoryPostProcessor {
034
035        /**
036         * Logger available to subclasses.
037         */
038        protected transient Log logger = LogFactory.getLog(getClass());
039
040        /**
041         * Set the name of the logger to use.
042         * The name will be passed to the underlying logger implementation through Commons Logging,
043         * getting interpreted as log category according to the logger's configuration.
044         * <p>This can be specified to not log into the category of this warner class but rather
045         * into a specific named category.
046         * @see org.apache.commons.logging.LogFactory#getLog(String)
047         * @see java.util.logging.Logger#getLogger(String)
048         */
049        public void setLoggerName(String loggerName) {
050                this.logger = LogFactory.getLog(loggerName);
051        }
052
053
054        @Override
055        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
056                if (isLogEnabled()) {
057                        String[] beanNames = beanFactory.getBeanDefinitionNames();
058                        for (String beanName : beanNames) {
059                                String nameToLookup = beanName;
060                                if (beanFactory.isFactoryBean(beanName)) {
061                                        nameToLookup = BeanFactory.FACTORY_BEAN_PREFIX + beanName;
062                                }
063                                Class<?> beanType = beanFactory.getType(nameToLookup);
064                                if (beanType != null) {
065                                        Class<?> userClass = ClassUtils.getUserClass(beanType);
066                                        if (userClass.isAnnotationPresent(Deprecated.class)) {
067                                                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
068                                                logDeprecatedBean(beanName, beanType, beanDefinition);
069                                        }
070                                }
071                        }
072                }
073        }
074
075        /**
076         * Logs a warning for a bean annotated with {@link Deprecated @Deprecated}.
077         * @param beanName the name of the deprecated bean
078         * @param beanType the user-specified type of the deprecated bean
079         * @param beanDefinition the definition of the deprecated bean
080         */
081        protected void logDeprecatedBean(String beanName, Class<?> beanType, BeanDefinition beanDefinition) {
082                StringBuilder builder = new StringBuilder();
083                builder.append(beanType);
084                builder.append(" ['");
085                builder.append(beanName);
086                builder.append('\'');
087                String resourceDescription = beanDefinition.getResourceDescription();
088                if (StringUtils.hasLength(resourceDescription)) {
089                        builder.append(" in ");
090                        builder.append(resourceDescription);
091                }
092                builder.append("] has been deprecated");
093                writeToLog(builder.toString());
094        }
095
096        /**
097         * Actually write to the underlying log.
098         * <p>The default implementations logs the message at "warn" level.
099         * @param message the message to write
100         */
101        protected void writeToLog(String message) {
102                logger.warn(message);
103        }
104
105        /**
106         * Determine whether the {@link #logger} field is enabled.
107         * <p>Default is {@code true} when the "warn" level is enabled.
108         * Subclasses can override this to change the level under which logging occurs.
109         */
110        protected boolean isLogEnabled() {
111                return logger.isWarnEnabled();
112        }
113
114}