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.factory.config.RuntimeBeanReference;
020import org.springframework.util.ObjectUtils;
021
022/**
023 * Programmatic means of constructing
024 * {@link org.springframework.beans.factory.config.BeanDefinition BeanDefinitions}
025 * using the builder pattern. Intended primarily for use when implementing Spring 2.0
026 * {@link org.springframework.beans.factory.xml.NamespaceHandler NamespaceHandlers}.
027 *
028 * @author Rod Johnson
029 * @author Rob Harrop
030 * @author Juergen Hoeller
031 * @since 2.0
032 */
033public class BeanDefinitionBuilder {
034
035        /**
036         * Create a new {@code BeanDefinitionBuilder} used to construct a {@link GenericBeanDefinition}.
037         */
038        public static BeanDefinitionBuilder genericBeanDefinition() {
039                BeanDefinitionBuilder builder = new BeanDefinitionBuilder();
040                builder.beanDefinition = new GenericBeanDefinition();
041                return builder;
042        }
043
044        /**
045         * Create a new {@code BeanDefinitionBuilder} used to construct a {@link GenericBeanDefinition}.
046         * @param beanClass the {@code Class} of the bean that the definition is being created for
047         */
048        public static BeanDefinitionBuilder genericBeanDefinition(Class<?> beanClass) {
049                BeanDefinitionBuilder builder = new BeanDefinitionBuilder();
050                builder.beanDefinition = new GenericBeanDefinition();
051                builder.beanDefinition.setBeanClass(beanClass);
052                return builder;
053        }
054
055        /**
056         * Create a new {@code BeanDefinitionBuilder} used to construct a {@link GenericBeanDefinition}.
057         * @param beanClassName the class name for the bean that the definition is being created for
058         */
059        public static BeanDefinitionBuilder genericBeanDefinition(String beanClassName) {
060                BeanDefinitionBuilder builder = new BeanDefinitionBuilder();
061                builder.beanDefinition = new GenericBeanDefinition();
062                builder.beanDefinition.setBeanClassName(beanClassName);
063                return builder;
064        }
065
066        /**
067         * Create a new {@code BeanDefinitionBuilder} used to construct a {@link RootBeanDefinition}.
068         * @param beanClass the {@code Class} of the bean that the definition is being created for
069         */
070        public static BeanDefinitionBuilder rootBeanDefinition(Class<?> beanClass) {
071                return rootBeanDefinition(beanClass, null);
072        }
073
074        /**
075         * Create a new {@code BeanDefinitionBuilder} used to construct a {@link RootBeanDefinition}.
076         * @param beanClass the {@code Class} of the bean that the definition is being created for
077         * @param factoryMethodName the name of the method to use to construct the bean instance
078         */
079        public static BeanDefinitionBuilder rootBeanDefinition(Class<?> beanClass, String factoryMethodName) {
080                BeanDefinitionBuilder builder = new BeanDefinitionBuilder();
081                builder.beanDefinition = new RootBeanDefinition();
082                builder.beanDefinition.setBeanClass(beanClass);
083                builder.beanDefinition.setFactoryMethodName(factoryMethodName);
084                return builder;
085        }
086
087        /**
088         * Create a new {@code BeanDefinitionBuilder} used to construct a {@link RootBeanDefinition}.
089         * @param beanClassName the class name for the bean that the definition is being created for
090         */
091        public static BeanDefinitionBuilder rootBeanDefinition(String beanClassName) {
092                return rootBeanDefinition(beanClassName, null);
093        }
094
095        /**
096         * Create a new {@code BeanDefinitionBuilder} used to construct a {@link RootBeanDefinition}.
097         * @param beanClassName the class name for the bean that the definition is being created for
098         * @param factoryMethodName the name of the method to use to construct the bean instance
099         */
100        public static BeanDefinitionBuilder rootBeanDefinition(String beanClassName, String factoryMethodName) {
101                BeanDefinitionBuilder builder = new BeanDefinitionBuilder();
102                builder.beanDefinition = new RootBeanDefinition();
103                builder.beanDefinition.setBeanClassName(beanClassName);
104                builder.beanDefinition.setFactoryMethodName(factoryMethodName);
105                return builder;
106        }
107
108        /**
109         * Create a new {@code BeanDefinitionBuilder} used to construct a {@link ChildBeanDefinition}.
110         * @param parentName the name of the parent bean
111         */
112        public static BeanDefinitionBuilder childBeanDefinition(String parentName) {
113                BeanDefinitionBuilder builder = new BeanDefinitionBuilder();
114                builder.beanDefinition = new ChildBeanDefinition(parentName);
115                return builder;
116        }
117
118
119        /**
120         * The {@code BeanDefinition} instance we are creating.
121         */
122        private AbstractBeanDefinition beanDefinition;
123
124        /**
125         * Our current position with respect to constructor args.
126         */
127        private int constructorArgIndex;
128
129
130        /**
131         * Enforce the use of factory methods.
132         */
133        private BeanDefinitionBuilder() {
134        }
135
136        /**
137         * Return the current BeanDefinition object in its raw (unvalidated) form.
138         * @see #getBeanDefinition()
139         */
140        public AbstractBeanDefinition getRawBeanDefinition() {
141                return this.beanDefinition;
142        }
143
144        /**
145         * Validate and return the created BeanDefinition object.
146         */
147        public AbstractBeanDefinition getBeanDefinition() {
148                this.beanDefinition.validate();
149                return this.beanDefinition;
150        }
151
152
153        /**
154         * Set the name of the parent definition of this bean definition.
155         */
156        public BeanDefinitionBuilder setParentName(String parentName) {
157                this.beanDefinition.setParentName(parentName);
158                return this;
159        }
160
161        /**
162         * Set the name of a static factory method to use for this definition,
163         * to be called on this bean's class.
164         */
165        public BeanDefinitionBuilder setFactoryMethod(String factoryMethod) {
166                this.beanDefinition.setFactoryMethodName(factoryMethod);
167                return this;
168        }
169
170        /**
171         * Set the name of a non-static factory method to use for this definition,
172         * including the bean name of the factory instance to call the method on.
173         * @since 4.3.6
174         */
175        public BeanDefinitionBuilder setFactoryMethodOnBean(String factoryMethod, String factoryBean) {
176                this.beanDefinition.setFactoryMethodName(factoryMethod);
177                this.beanDefinition.setFactoryBeanName(factoryBean);
178                return this;
179        }
180
181        /**
182         * Add an indexed constructor arg value. The current index is tracked internally
183         * and all additions are at the present point.
184         * @deprecated since Spring 2.5, in favor of {@link #addConstructorArgValue}.
185         * This variant just remains around for Spring Security 2.x compatibility.
186         */
187        @Deprecated
188        public BeanDefinitionBuilder addConstructorArg(Object value) {
189                return addConstructorArgValue(value);
190        }
191
192        /**
193         * Add an indexed constructor arg value. The current index is tracked internally
194         * and all additions are at the present point.
195         */
196        public BeanDefinitionBuilder addConstructorArgValue(Object value) {
197                this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(
198                                this.constructorArgIndex++, value);
199                return this;
200        }
201
202        /**
203         * Add a reference to a named bean as a constructor arg.
204         * @see #addConstructorArgValue(Object)
205         */
206        public BeanDefinitionBuilder addConstructorArgReference(String beanName) {
207                this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(
208                                this.constructorArgIndex++, new RuntimeBeanReference(beanName));
209                return this;
210        }
211
212        /**
213         * Add the supplied property value under the given name.
214         */
215        public BeanDefinitionBuilder addPropertyValue(String name, Object value) {
216                this.beanDefinition.getPropertyValues().add(name, value);
217                return this;
218        }
219
220        /**
221         * Add a reference to the specified bean name under the property specified.
222         * @param name the name of the property to add the reference to
223         * @param beanName the name of the bean being referenced
224         */
225        public BeanDefinitionBuilder addPropertyReference(String name, String beanName) {
226                this.beanDefinition.getPropertyValues().add(name, new RuntimeBeanReference(beanName));
227                return this;
228        }
229
230        /**
231         * Set the init method for this definition.
232         */
233        public BeanDefinitionBuilder setInitMethodName(String methodName) {
234                this.beanDefinition.setInitMethodName(methodName);
235                return this;
236        }
237
238        /**
239         * Set the destroy method for this definition.
240         */
241        public BeanDefinitionBuilder setDestroyMethodName(String methodName) {
242                this.beanDefinition.setDestroyMethodName(methodName);
243                return this;
244        }
245
246
247        /**
248         * Set the scope of this definition.
249         * @see org.springframework.beans.factory.config.BeanDefinition#SCOPE_SINGLETON
250         * @see org.springframework.beans.factory.config.BeanDefinition#SCOPE_PROTOTYPE
251         */
252        public BeanDefinitionBuilder setScope(String scope) {
253                this.beanDefinition.setScope(scope);
254                return this;
255        }
256
257        /**
258         * Set whether or not this definition is abstract.
259         */
260        public BeanDefinitionBuilder setAbstract(boolean flag) {
261                this.beanDefinition.setAbstract(flag);
262                return this;
263        }
264
265        /**
266         * Set whether beans for this definition should be lazily initialized or not.
267         */
268        public BeanDefinitionBuilder setLazyInit(boolean lazy) {
269                this.beanDefinition.setLazyInit(lazy);
270                return this;
271        }
272
273        /**
274         * Set the autowire mode for this definition.
275         */
276        public BeanDefinitionBuilder setAutowireMode(int autowireMode) {
277                beanDefinition.setAutowireMode(autowireMode);
278                return this;
279        }
280
281        /**
282         * Set the depency check mode for this definition.
283         */
284        public BeanDefinitionBuilder setDependencyCheck(int dependencyCheck) {
285                beanDefinition.setDependencyCheck(dependencyCheck);
286                return this;
287        }
288
289        /**
290         * Append the specified bean name to the list of beans that this definition
291         * depends on.
292         */
293        public BeanDefinitionBuilder addDependsOn(String beanName) {
294                if (this.beanDefinition.getDependsOn() == null) {
295                        this.beanDefinition.setDependsOn(beanName);
296                }
297                else {
298                        String[] added = ObjectUtils.addObjectToArray(this.beanDefinition.getDependsOn(), beanName);
299                        this.beanDefinition.setDependsOn(added);
300                }
301                return this;
302        }
303
304        /**
305         * Set the role of this definition.
306         */
307        public BeanDefinitionBuilder setRole(int role) {
308                this.beanDefinition.setRole(role);
309                return this;
310        }
311
312}