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