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.support;
018
019import org.springframework.beans.MutablePropertyValues;
020import org.springframework.beans.factory.config.ConstructorArgumentValues;
021import org.springframework.lang.Nullable;
022import org.springframework.util.ObjectUtils;
023
024/**
025 * Bean definition for beans which inherit settings from their parent.
026 * Child bean definitions have a fixed dependency on a parent bean definition.
027 *
028 * <p>A child bean definition will inherit constructor argument values,
029 * property values and method overrides from the parent, with the option
030 * to add new values. If init method, destroy method and/or static factory
031 * method are specified, they will override the corresponding parent settings.
032 * The remaining settings will <i>always</i> be taken from the child definition:
033 * depends on, autowire mode, dependency check, singleton, lazy init.
034 *
035 * <p><b>NOTE:</b> Since Spring 2.5, the preferred way to register bean
036 * definitions programmatically is the {@link GenericBeanDefinition} class,
037 * which allows to dynamically define parent dependencies through the
038 * {@link GenericBeanDefinition#setParentName} method. This effectively
039 * supersedes the ChildBeanDefinition class for most use cases.
040 *
041 * @author Rod Johnson
042 * @author Juergen Hoeller
043 * @see GenericBeanDefinition
044 * @see RootBeanDefinition
045 */
046@SuppressWarnings("serial")
047public class ChildBeanDefinition extends AbstractBeanDefinition {
048
049        @Nullable
050        private String parentName;
051
052
053        /**
054         * Create a new ChildBeanDefinition for the given parent, to be
055         * configured through its bean properties and configuration methods.
056         * @param parentName the name of the parent bean
057         * @see #setBeanClass
058         * @see #setScope
059         * @see #setConstructorArgumentValues
060         * @see #setPropertyValues
061         */
062        public ChildBeanDefinition(String parentName) {
063                super();
064                this.parentName = parentName;
065        }
066
067        /**
068         * Create a new ChildBeanDefinition for the given parent.
069         * @param parentName the name of the parent bean
070         * @param pvs the additional property values of the child
071         */
072        public ChildBeanDefinition(String parentName, MutablePropertyValues pvs) {
073                super(null, pvs);
074                this.parentName = parentName;
075        }
076
077        /**
078         * Create a new ChildBeanDefinition for the given parent.
079         * @param parentName the name of the parent bean
080         * @param cargs the constructor argument values to apply
081         * @param pvs the additional property values of the child
082         */
083        public ChildBeanDefinition(
084                        String parentName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
085
086                super(cargs, pvs);
087                this.parentName = parentName;
088        }
089
090        /**
091         * Create a new ChildBeanDefinition for the given parent,
092         * providing constructor arguments and property values.
093         * @param parentName the name of the parent bean
094         * @param beanClass the class of the bean to instantiate
095         * @param cargs the constructor argument values to apply
096         * @param pvs the property values to apply
097         */
098        public ChildBeanDefinition(
099                        String parentName, Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
100
101                super(cargs, pvs);
102                this.parentName = parentName;
103                setBeanClass(beanClass);
104        }
105
106        /**
107         * Create a new ChildBeanDefinition for the given parent,
108         * providing constructor arguments and property values.
109         * Takes a bean class name to avoid eager loading of the bean class.
110         * @param parentName the name of the parent bean
111         * @param beanClassName the name of the class to instantiate
112         * @param cargs the constructor argument values to apply
113         * @param pvs the property values to apply
114         */
115        public ChildBeanDefinition(
116                        String parentName, String beanClassName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {
117
118                super(cargs, pvs);
119                this.parentName = parentName;
120                setBeanClassName(beanClassName);
121        }
122
123        /**
124         * Create a new ChildBeanDefinition as deep copy of the given
125         * bean definition.
126         * @param original the original bean definition to copy from
127         */
128        public ChildBeanDefinition(ChildBeanDefinition original) {
129                super(original);
130        }
131
132
133        @Override
134        public void setParentName(@Nullable String parentName) {
135                this.parentName = parentName;
136        }
137
138        @Override
139        @Nullable
140        public String getParentName() {
141                return this.parentName;
142        }
143
144        @Override
145        public void validate() throws BeanDefinitionValidationException {
146                super.validate();
147                if (this.parentName == null) {
148                        throw new BeanDefinitionValidationException("'parentName' must be set in ChildBeanDefinition");
149                }
150        }
151
152
153        @Override
154        public AbstractBeanDefinition cloneBeanDefinition() {
155                return new ChildBeanDefinition(this);
156        }
157
158        @Override
159        public boolean equals(@Nullable Object other) {
160                if (this == other) {
161                        return true;
162                }
163                if (!(other instanceof ChildBeanDefinition)) {
164                        return false;
165                }
166                ChildBeanDefinition that = (ChildBeanDefinition) other;
167                return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName) && super.equals(other));
168        }
169
170        @Override
171        public int hashCode() {
172                return ObjectUtils.nullSafeHashCode(this.parentName) * 29 + super.hashCode();
173        }
174
175        @Override
176        public String toString() {
177                return "Child bean with parent '" + this.parentName + "': " + super.toString();
178        }
179
180}