1 16 17 package org.springframework.beans.factory.support; 18 19 import java.lang.reflect.Constructor ; 20 import java.lang.reflect.Method ; 21 import java.lang.reflect.Modifier ; 22 import java.util.HashSet ; 23 import java.util.Iterator ; 24 import java.util.Map ; 25 import java.util.Set ; 26 27 import org.springframework.beans.BeanWrapper; 28 import org.springframework.beans.BeanWrapperImpl; 29 import org.springframework.beans.BeansException; 30 import org.springframework.beans.TypeMismatchException; 31 import org.springframework.beans.factory.BeanCreationException; 32 import org.springframework.beans.factory.BeanDefinitionStoreException; 33 import org.springframework.beans.factory.UnsatisfiedDependencyException; 34 import org.springframework.beans.factory.config.ConstructorArgumentValues; 35 import org.springframework.core.MethodParameter; 36 import org.springframework.util.ObjectUtils; 37 import org.springframework.util.ReflectionUtils; 38 39 52 abstract class ConstructorResolver { 53 54 private final AbstractBeanFactory beanFactory; 55 56 private final InstantiationStrategy instantiationStrategy; 57 58 59 64 public ConstructorResolver(AbstractBeanFactory beanFactory, InstantiationStrategy instantiationStrategy) { 65 this.beanFactory = beanFactory; 66 this.instantiationStrategy = instantiationStrategy; 67 } 68 69 70 81 protected BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd) { 82 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); 83 ConstructorArgumentValues resolvedValues = new ConstructorArgumentValues(); 84 85 BeanWrapper bw = new BeanWrapperImpl(); 86 this.beanFactory.initBeanWrapper(bw); 87 88 int minNrOfArgs = 0; 89 if (cargs != null) { 90 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); 91 } 92 93 Constructor [] candidates = mbd.getBeanClass().getDeclaredConstructors(); 94 AutowireUtils.sortConstructors(candidates); 95 96 Constructor constructorToUse = null; 97 Object [] argsToUse = null; 98 int minTypeDiffWeight = Integer.MAX_VALUE; 99 100 for (int i = 0; i < candidates.length; i++) { 101 Constructor constructor = candidates[i]; 102 103 if (constructorToUse != null && 104 constructorToUse.getParameterTypes().length > constructor.getParameterTypes().length) { 105 break; 108 } 109 if (constructor.getParameterTypes().length < minNrOfArgs) { 110 throw new BeanCreationException(mbd.getResourceDescription(), beanName, 111 minNrOfArgs + " constructor arguments specified but no matching constructor found in bean '" + 112 beanName + "' " + 113 "(hint: specify index and/or type arguments for simple parameters to avoid type ambiguities)"); 114 } 115 116 try { 118 Class [] paramTypes = constructor.getParameterTypes(); 119 ArgumentsHolder args = createArgumentArray( 120 beanName, mbd, resolvedValues, bw, paramTypes, constructor); 121 122 int typeDiffWeight = args.getTypeDifferenceWeight(paramTypes); 123 if (typeDiffWeight < minTypeDiffWeight) { 125 constructorToUse = constructor; 126 argsToUse = args.arguments; 127 minTypeDiffWeight = typeDiffWeight; 128 } 129 } 130 catch (UnsatisfiedDependencyException ex) { 131 if (this.beanFactory.logger.isTraceEnabled()) { 132 this.beanFactory.logger.trace("Ignoring constructor [" + constructor + "] of bean '" + beanName + 133 "': " + ex); 134 } 135 if (i == candidates.length - 1 && constructorToUse == null) { 136 throw ex; 137 } 138 else { 139 } 141 } 142 } 143 144 if (constructorToUse == null) { 145 throw new BeanCreationException( 146 mbd.getResourceDescription(), beanName, "Could not resolve matching constructor"); 147 } 148 149 Object beanInstance = this.instantiationStrategy.instantiate( 150 mbd, beanName, this.beanFactory, constructorToUse, argsToUse); 151 bw.setWrappedInstance(beanInstance); 152 if (this.beanFactory.logger.isDebugEnabled()) { 153 this.beanFactory.logger.debug("Bean '" + beanName + "' instantiated via constructor [" + constructorToUse + "]"); 154 } 155 return bw; 156 } 157 158 173 public BeanWrapper instantiateUsingFactoryMethod(String beanName, RootBeanDefinition mbd, Object [] explicitArgs) { 174 BeanWrapper bw = new BeanWrapperImpl(); 175 this.beanFactory.initBeanWrapper(bw); 176 177 ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues(); 178 ConstructorArgumentValues resolvedValues = null; 179 180 int minNrOfArgs = 0; 181 if (explicitArgs == null) { 182 resolvedValues = new ConstructorArgumentValues(); 185 minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues); 186 } 187 else { 188 minNrOfArgs = explicitArgs.length; 189 } 190 191 boolean isStatic = true; 192 Class factoryClass = null; 193 Object factoryBean = null; 194 195 if (mbd.getFactoryBeanName() != null) { 196 factoryBean = this.beanFactory.getBean(mbd.getFactoryBeanName()); 197 factoryClass = factoryBean.getClass(); 198 isStatic = false; 199 } 200 else { 201 factoryClass = mbd.getBeanClass(); 203 } 204 205 Method [] candidates = ReflectionUtils.getAllDeclaredMethods(factoryClass); 207 208 Method factoryMethodToUse = null; 209 Object [] argsToUse = null; 210 int minTypeDiffWeight = Integer.MAX_VALUE; 211 212 for (int i = 0; i < candidates.length; i++) { 213 Method factoryMethod = candidates[i]; 214 215 if (Modifier.isStatic(factoryMethod.getModifiers()) == isStatic && 216 factoryMethod.getName().equals(mbd.getFactoryMethodName()) && 217 factoryMethod.getParameterTypes().length >= minNrOfArgs) { 218 219 Class [] paramTypes = factoryMethod.getParameterTypes(); 220 ArgumentsHolder args = null; 221 222 if (resolvedValues != null) { 223 try { 225 args = createArgumentArray( 226 beanName, mbd, resolvedValues, bw, paramTypes, factoryMethod); 227 } 228 catch (UnsatisfiedDependencyException ex) { 229 if (this.beanFactory.logger.isTraceEnabled()) { 230 this.beanFactory.logger.trace("Ignoring factory method [" + factoryMethod + 231 "] of bean '" + beanName + "': " + ex); 232 } 233 if (i == candidates.length - 1 && factoryMethodToUse == null) { 234 throw ex; 235 } 236 else { 237 continue; 239 } 240 } 241 } 242 243 else { 244 if (paramTypes.length != explicitArgs.length) { 246 continue; 247 } 248 args = new ArgumentsHolder(explicitArgs); 249 } 250 251 int typeDiffWeight = args.getTypeDifferenceWeight(paramTypes); 252 if (typeDiffWeight < minTypeDiffWeight) { 254 factoryMethodToUse = factoryMethod; 255 argsToUse = args.arguments; 256 minTypeDiffWeight = typeDiffWeight; 257 } 258 } 259 } 260 261 if (factoryMethodToUse == null) { 262 throw new BeanDefinitionStoreException("No matching factory method found: " + 263 (mbd.getFactoryBeanName() != null ? 264 "factory bean '" + mbd.getFactoryBeanName() + "'; " : "") + 265 "factory method '" + mbd.getFactoryMethodName() + "'"); 266 } 267 if (!factoryMethodToUse.isAccessible()) { 268 factoryMethodToUse.setAccessible(true); 269 } 270 271 Object beanInstance = this.instantiationStrategy.instantiate( 272 mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse); 273 if (beanInstance == null) { 274 return null; 275 } 276 277 bw.setWrappedInstance(beanInstance); 278 if (this.beanFactory.logger.isDebugEnabled()) { 279 this.beanFactory.logger.debug( 280 "Bean '" + beanName + "' instantiated via factory method '" + factoryMethodToUse + "'"); 281 } 282 return bw; 283 } 284 285 290 private int resolveConstructorArguments( 291 String beanName, RootBeanDefinition mbd, BeanWrapper bw, 292 ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) { 293 294 BeanDefinitionValueResolver valueResolver = 295 new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, bw); 296 297 int minNrOfArgs = cargs.getArgumentCount(); 298 299 for (Iterator it = cargs.getIndexedArgumentValues().entrySet().iterator(); it.hasNext();) { 300 Map.Entry entry = (Map.Entry ) it.next(); 301 int index = ((Integer ) entry.getKey()).intValue(); 302 if (index < 0) { 303 throw new BeanCreationException(mbd.getResourceDescription(), beanName, 304 "Invalid constructor argument index: " + index); 305 } 306 if (index > minNrOfArgs) { 307 minNrOfArgs = index + 1; 308 } 309 String argName = "constructor argument with index " + index; 310 ConstructorArgumentValues.ValueHolder valueHolder = 311 (ConstructorArgumentValues.ValueHolder) entry.getValue(); 312 Object resolvedValue = valueResolver.resolveValueIfNecessary(argName, valueHolder.getValue()); 313 resolvedValues.addIndexedArgumentValue(index, resolvedValue, valueHolder.getType()); 314 } 315 316 for (Iterator it = cargs.getGenericArgumentValues().iterator(); it.hasNext();) { 317 ConstructorArgumentValues.ValueHolder valueHolder = 318 (ConstructorArgumentValues.ValueHolder) it.next(); 319 String argName = "constructor argument"; 320 Object resolvedValue = valueResolver.resolveValueIfNecessary(argName, valueHolder.getValue()); 321 resolvedValues.addGenericArgumentValue(resolvedValue, valueHolder.getType()); 322 } 323 324 return minNrOfArgs; 325 } 326 327 331 private ArgumentsHolder createArgumentArray( 332 String beanName, RootBeanDefinition mbd, ConstructorArgumentValues resolvedValues, 333 BeanWrapper bw, Class [] paramTypes, Object methodOrCtor) 334 throws UnsatisfiedDependencyException { 335 336 String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method"); 337 338 ArgumentsHolder args = new ArgumentsHolder(paramTypes.length); 339 Set usedValueHolders = new HashSet (paramTypes.length); 340 341 for (int index = 0; index < paramTypes.length; index++) { 342 ConstructorArgumentValues.ValueHolder valueHolder = 344 resolvedValues.getArgumentValue(index, paramTypes[index], usedValueHolders); 345 if (valueHolder == null && 349 mbd.getResolvedAutowireMode() != RootBeanDefinition.AUTOWIRE_CONSTRUCTOR) { 350 valueHolder = resolvedValues.getGenericArgumentValue(null, usedValueHolders); 351 } 352 if (valueHolder != null) { 353 usedValueHolders.add(valueHolder); 356 args.rawArguments[index] = valueHolder.getValue(); 357 try { 358 args.arguments[index] = 359 this.beanFactory.doTypeConversionIfNecessary(bw, args.rawArguments[index], 360 paramTypes[index], MethodParameter.forMethodOrConstructor(methodOrCtor, index)); 361 } 362 catch (TypeMismatchException ex) { 363 throw new UnsatisfiedDependencyException( 364 mbd.getResourceDescription(), beanName, index, paramTypes[index], 365 "Could not convert " + methodType + " argument value of type [" + 366 ObjectUtils.nullSafeClassName(valueHolder.getValue()) + 367 "] to required type [" + paramTypes[index].getName() + "]: " + ex.getMessage()); 368 } 369 } 370 else { 371 if (mbd.getResolvedAutowireMode() != RootBeanDefinition.AUTOWIRE_CONSTRUCTOR) { 374 throw new UnsatisfiedDependencyException( 375 mbd.getResourceDescription(), beanName, index, paramTypes[index], 376 "Ambiguous " + methodType + " argument types - " + 377 "did you specify the correct bean references as " + methodType + " arguments?"); 378 } 379 Map matchingBeans = findAutowireCandidates(beanName, paramTypes[index]); 380 if (matchingBeans.size() != 1) { 381 throw new UnsatisfiedDependencyException( 382 mbd.getResourceDescription(), beanName, index, paramTypes[index], 383 "There are " + matchingBeans.size() + " beans of type [" + paramTypes[index].getName() + 384 "] available for autowiring: " + matchingBeans.keySet() + 385 ". There should have been exactly 1 to be able to autowire " + 386 methodType + " of bean '" + beanName + "'."); 387 } 388 Map.Entry entry = (Map.Entry ) matchingBeans.entrySet().iterator().next(); 389 String autowiredBeanName = (String ) entry.getKey(); 390 Object autowiredBean = entry.getValue(); 391 args.rawArguments[index] = autowiredBean; 392 args.arguments[index] = autowiredBean; 393 if (mbd.isSingleton()) { 394 this.beanFactory.registerDependentBean(autowiredBeanName, beanName); 395 } 396 if (this.beanFactory.logger.isDebugEnabled()) { 397 this.beanFactory.logger.debug("Autowiring by type from bean name '" + beanName + 398 "' via " + methodType + " to bean named '" + autowiredBeanName + "'"); 399 } 400 } 401 } 402 return args; 403 } 404 405 406 418 protected abstract Map findAutowireCandidates(String beanName, Class requiredType) throws BeansException; 419 420 421 424 private static class ArgumentsHolder { 425 426 public Object rawArguments[]; 427 428 public Object arguments[]; 429 430 public ArgumentsHolder(int size) { 431 this.rawArguments = new Object [size]; 432 this.arguments = new Object [size]; 433 } 434 435 public ArgumentsHolder(Object [] args) { 436 this.rawArguments = args; 437 this.arguments = args; 438 } 439 440 public int getTypeDifferenceWeight(Class [] paramTypes) { 441 int typeDiffWeight = AutowireUtils.getTypeDifferenceWeight(paramTypes, this.arguments); 446 int rawTypeDiffWeight = AutowireUtils.getTypeDifferenceWeight(paramTypes, this.rawArguments) - 1024; 447 return (rawTypeDiffWeight < typeDiffWeight ? rawTypeDiffWeight : typeDiffWeight); 448 } 449 } 450 451 } 452 | Popular Tags |