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.springframework.beans.BeanMetadataElement;
020import org.springframework.beans.factory.BeanFactoryUtils;
021import org.springframework.lang.Nullable;
022import org.springframework.util.Assert;
023import org.springframework.util.ObjectUtils;
024import org.springframework.util.StringUtils;
025
026/**
027 * Holder for a BeanDefinition with name and aliases.
028 * Can be registered as a placeholder for an inner bean.
029 *
030 * <p>Can also be used for programmatic registration of inner bean
031 * definitions. If you don't care about BeanNameAware and the like,
032 * registering RootBeanDefinition or ChildBeanDefinition is good enough.
033 *
034 * @author Juergen Hoeller
035 * @since 1.0.2
036 * @see org.springframework.beans.factory.BeanNameAware
037 * @see org.springframework.beans.factory.support.RootBeanDefinition
038 * @see org.springframework.beans.factory.support.ChildBeanDefinition
039 */
040public class BeanDefinitionHolder implements BeanMetadataElement {
041
042        private final BeanDefinition beanDefinition;
043
044        private final String beanName;
045
046        @Nullable
047        private final String[] aliases;
048
049
050        /**
051         * Create a new BeanDefinitionHolder.
052         * @param beanDefinition the BeanDefinition to wrap
053         * @param beanName the name of the bean, as specified for the bean definition
054         */
055        public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName) {
056                this(beanDefinition, beanName, null);
057        }
058
059        /**
060         * Create a new BeanDefinitionHolder.
061         * @param beanDefinition the BeanDefinition to wrap
062         * @param beanName the name of the bean, as specified for the bean definition
063         * @param aliases alias names for the bean, or {@code null} if none
064         */
065        public BeanDefinitionHolder(BeanDefinition beanDefinition, String beanName, @Nullable String[] aliases) {
066                Assert.notNull(beanDefinition, "BeanDefinition must not be null");
067                Assert.notNull(beanName, "Bean name must not be null");
068                this.beanDefinition = beanDefinition;
069                this.beanName = beanName;
070                this.aliases = aliases;
071        }
072
073        /**
074         * Copy constructor: Create a new BeanDefinitionHolder with the
075         * same contents as the given BeanDefinitionHolder instance.
076         * <p>Note: The wrapped BeanDefinition reference is taken as-is;
077         * it is {@code not} deeply copied.
078         * @param beanDefinitionHolder the BeanDefinitionHolder to copy
079         */
080        public BeanDefinitionHolder(BeanDefinitionHolder beanDefinitionHolder) {
081                Assert.notNull(beanDefinitionHolder, "BeanDefinitionHolder must not be null");
082                this.beanDefinition = beanDefinitionHolder.getBeanDefinition();
083                this.beanName = beanDefinitionHolder.getBeanName();
084                this.aliases = beanDefinitionHolder.getAliases();
085        }
086
087
088        /**
089         * Return the wrapped BeanDefinition.
090         */
091        public BeanDefinition getBeanDefinition() {
092                return this.beanDefinition;
093        }
094
095        /**
096         * Return the primary name of the bean, as specified for the bean definition.
097         */
098        public String getBeanName() {
099                return this.beanName;
100        }
101
102        /**
103         * Return the alias names for the bean, as specified directly for the bean definition.
104         * @return the array of alias names, or {@code null} if none
105         */
106        @Nullable
107        public String[] getAliases() {
108                return this.aliases;
109        }
110
111        /**
112         * Expose the bean definition's source object.
113         * @see BeanDefinition#getSource()
114         */
115        @Override
116        @Nullable
117        public Object getSource() {
118                return this.beanDefinition.getSource();
119        }
120
121        /**
122         * Determine whether the given candidate name matches the bean name
123         * or the aliases stored in this bean definition.
124         */
125        public boolean matchesName(@Nullable String candidateName) {
126                return (candidateName != null && (candidateName.equals(this.beanName) ||
127                                candidateName.equals(BeanFactoryUtils.transformedBeanName(this.beanName)) ||
128                                ObjectUtils.containsElement(this.aliases, candidateName)));
129        }
130
131
132        /**
133         * Return a friendly, short description for the bean, stating name and aliases.
134         * @see #getBeanName()
135         * @see #getAliases()
136         */
137        public String getShortDescription() {
138                if (this.aliases == null) {
139                        return "Bean definition with name '" + this.beanName + "'";
140                }
141                return "Bean definition with name '" + this.beanName + "' and aliases [" + StringUtils.arrayToCommaDelimitedString(this.aliases) + ']';
142        }
143
144        /**
145         * Return a long description for the bean, including name and aliases
146         * as well as a description of the contained {@link BeanDefinition}.
147         * @see #getShortDescription()
148         * @see #getBeanDefinition()
149         */
150        public String getLongDescription() {
151                return getShortDescription() + ": " + this.beanDefinition;
152        }
153
154        /**
155         * This implementation returns the long description. Can be overridden
156         * to return the short description or any kind of custom description instead.
157         * @see #getLongDescription()
158         * @see #getShortDescription()
159         */
160        @Override
161        public String toString() {
162                return getLongDescription();
163        }
164
165
166        @Override
167        public boolean equals(@Nullable Object other) {
168                if (this == other) {
169                        return true;
170                }
171                if (!(other instanceof BeanDefinitionHolder)) {
172                        return false;
173                }
174                BeanDefinitionHolder otherHolder = (BeanDefinitionHolder) other;
175                return this.beanDefinition.equals(otherHolder.beanDefinition) &&
176                                this.beanName.equals(otherHolder.beanName) &&
177                                ObjectUtils.nullSafeEquals(this.aliases, otherHolder.aliases);
178        }
179
180        @Override
181        public int hashCode() {
182                int hashCode = this.beanDefinition.hashCode();
183                hashCode = 29 * hashCode + this.beanName.hashCode();
184                hashCode = 29 * hashCode + ObjectUtils.nullSafeHashCode(this.aliases);
185                return hashCode;
186        }
187
188}