Source Code Cross Referenced for ConstructorResolver.java in  » J2EE » spring-framework-2.5 » org » springframework » beans » factory » support » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » spring framework 2.5 » org.springframework.beans.factory.support 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2002-2007 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:         *      http://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:
017:        package org.springframework.beans.factory.support;
018:
019:        import java.lang.reflect.Constructor;
020:        import java.lang.reflect.Method;
021:        import java.lang.reflect.Modifier;
022:        import java.util.HashSet;
023:        import java.util.Iterator;
024:        import java.util.LinkedHashSet;
025:        import java.util.Map;
026:        import java.util.Set;
027:
028:        import org.springframework.beans.BeanMetadataElement;
029:        import org.springframework.beans.BeanWrapper;
030:        import org.springframework.beans.BeanWrapperImpl;
031:        import org.springframework.beans.BeansException;
032:        import org.springframework.beans.TypeConverter;
033:        import org.springframework.beans.TypeMismatchException;
034:        import org.springframework.beans.factory.BeanCreationException;
035:        import org.springframework.beans.factory.UnsatisfiedDependencyException;
036:        import org.springframework.beans.factory.config.ConstructorArgumentValues;
037:        import org.springframework.beans.factory.config.TypedStringValue;
038:        import org.springframework.core.MethodParameter;
039:        import org.springframework.util.ObjectUtils;
040:        import org.springframework.util.ReflectionUtils;
041:
042:        /**
043:         * Helper class for resolving constructors and factory methods.
044:         * Performs constructor resolution through argument matching.
045:         *
046:         * <p>Operates on an {@link AbstractBeanFactory} and an {@link InstantiationStrategy}.
047:         * Used by {@link AbstractAutowireCapableBeanFactory}.
048:         *
049:         * @author Juergen Hoeller
050:         * @author Rob Harrop
051:         * @author Mark Fisher
052:         * @since 2.0
053:         * @see #autowireConstructor
054:         * @see #instantiateUsingFactoryMethod
055:         * @see AbstractAutowireCapableBeanFactory
056:         */
057:        abstract class ConstructorResolver {
058:
059:            private final AbstractBeanFactory beanFactory;
060:
061:            private final InstantiationStrategy instantiationStrategy;
062:
063:            private final TypeConverter typeConverter;
064:
065:            /**
066:             * Create a new ConstructorResolver for the given factory and instantiation strategy.
067:             * @param beanFactory the BeanFactory to work with
068:             * @param instantiationStrategy the instantiate strategy for creating bean instances
069:             * @param typeConverter the TypeConverter to use (or <code>null</code> for using the default)
070:             */
071:            public ConstructorResolver(AbstractBeanFactory beanFactory,
072:                    InstantiationStrategy instantiationStrategy,
073:                    TypeConverter typeConverter) {
074:
075:                this .beanFactory = beanFactory;
076:                this .instantiationStrategy = instantiationStrategy;
077:                this .typeConverter = typeConverter;
078:            }
079:
080:            /**
081:             * "autowire constructor" (with constructor arguments by type) behavior.
082:             * Also applied if explicit constructor argument values are specified,
083:             * matching all remaining arguments with beans from the bean factory.
084:             * <p>This corresponds to constructor injection: In this mode, a Spring
085:             * bean factory is able to host components that expect constructor-based
086:             * dependency resolution.
087:             * @param beanName the name of the bean
088:             * @param mbd the merged bean definition for the bean
089:             * @param chosenCtors chosen candidate constructors (or <code>null</code> if none)
090:             * @param explicitArgs argument values passed in programmatically via the getBean method,
091:             * or <code>null</code> if none (-> use constructor argument values from bean definition)
092:             * @return a BeanWrapper for the new instance
093:             */
094:            protected BeanWrapper autowireConstructor(String beanName,
095:                    RootBeanDefinition mbd, Constructor[] chosenCtors,
096:                    Object[] explicitArgs) {
097:
098:                BeanWrapper bw = new BeanWrapperImpl();
099:                this .beanFactory.initBeanWrapper(bw);
100:
101:                Constructor constructorToUse = null;
102:                Object[] argsToUse = null;
103:
104:                if (explicitArgs != null) {
105:                    argsToUse = explicitArgs;
106:                } else {
107:                    constructorToUse = (Constructor) mbd.resolvedConstructorOrFactoryMethod;
108:                    if (constructorToUse != null) {
109:                        // Found a cached constructor...
110:                        argsToUse = mbd.resolvedConstructorArguments;
111:                        if (argsToUse == null) {
112:                            Class[] paramTypes = constructorToUse
113:                                    .getParameterTypes();
114:                            Object[] argsToResolve = mbd.preparedConstructorArguments;
115:                            TypeConverter converter = (this .typeConverter != null ? this .typeConverter
116:                                    : bw);
117:                            BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(
118:                                    this .beanFactory, beanName, mbd, converter);
119:                            argsToUse = new Object[argsToResolve.length];
120:                            for (int i = 0; i < argsToResolve.length; i++) {
121:                                Object argValue = argsToResolve[i];
122:                                if (argValue instanceof  AutowiredArgumentMarker) {
123:                                    argValue = resolveAutowiredArgument(
124:                                            new MethodParameter(
125:                                                    constructorToUse, i),
126:                                            beanName, null, converter);
127:                                } else if (argValue instanceof  BeanMetadataElement) {
128:                                    argValue = valueResolver
129:                                            .resolveValueIfNecessary(
130:                                                    "constructor argument",
131:                                                    argValue);
132:                                }
133:                                argsToUse[i] = converter
134:                                        .convertIfNecessary(argValue,
135:                                                paramTypes[i],
136:                                                new MethodParameter(
137:                                                        constructorToUse, i));
138:                            }
139:                        }
140:                    }
141:                }
142:
143:                if (constructorToUse == null) {
144:                    // Need to resolve the constructor.
145:                    boolean autowiring = (chosenCtors != null || mbd
146:                            .getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
147:                    ConstructorArgumentValues resolvedValues = null;
148:
149:                    int minNrOfArgs = 0;
150:                    if (explicitArgs != null) {
151:                        minNrOfArgs = explicitArgs.length;
152:                    } else {
153:                        ConstructorArgumentValues cargs = mbd
154:                                .getConstructorArgumentValues();
155:                        resolvedValues = new ConstructorArgumentValues();
156:                        minNrOfArgs = resolveConstructorArguments(beanName,
157:                                mbd, bw, cargs, resolvedValues);
158:                    }
159:
160:                    // Take specified constructors, if any.
161:                    Constructor[] candidates = (chosenCtors != null ? chosenCtors
162:                            : mbd.getBeanClass().getDeclaredConstructors());
163:                    AutowireUtils.sortConstructors(candidates);
164:                    int minTypeDiffWeight = Integer.MAX_VALUE;
165:
166:                    for (int i = 0; i < candidates.length; i++) {
167:                        Constructor candidate = candidates[i];
168:                        Class[] paramTypes = candidate.getParameterTypes();
169:
170:                        if (constructorToUse != null
171:                                && argsToUse.length > paramTypes.length) {
172:                            // Already found greedy constructor that can be satisfied ->
173:                            // do not look any further, there are only less greedy constructors left.
174:                            break;
175:                        }
176:                        if (paramTypes.length < minNrOfArgs) {
177:                            throw new BeanCreationException(
178:                                    mbd.getResourceDescription(),
179:                                    beanName,
180:                                    minNrOfArgs
181:                                            + " constructor arguments specified but no matching constructor found in bean '"
182:                                            + beanName
183:                                            + "' "
184:                                            + "(hint: specify index and/or type arguments for simple parameters to avoid type ambiguities)");
185:                        }
186:
187:                        ArgumentsHolder args = null;
188:
189:                        if (resolvedValues != null) {
190:                            // Try to resolve arguments for current constructor.
191:                            try {
192:                                args = createArgumentArray(beanName, mbd,
193:                                        resolvedValues, bw, paramTypes,
194:                                        candidate, autowiring);
195:                            } catch (UnsatisfiedDependencyException ex) {
196:                                if (this .beanFactory.logger.isTraceEnabled()) {
197:                                    this .beanFactory.logger
198:                                            .trace("Ignoring constructor ["
199:                                                    + candidate + "] of bean '"
200:                                                    + beanName + "': " + ex);
201:                                }
202:                                if (i == candidates.length - 1
203:                                        && constructorToUse == null) {
204:                                    throw ex;
205:                                } else {
206:                                    // Swallow and try next constructor.
207:                                    this .beanFactory.onSuppressedException(ex);
208:                                    continue;
209:                                }
210:                            }
211:                        }
212:
213:                        else {
214:                            // Explicit arguments given -> arguments length must match exactly.
215:                            if (paramTypes.length != explicitArgs.length) {
216:                                continue;
217:                            }
218:                            args = new ArgumentsHolder(explicitArgs);
219:                        }
220:
221:                        int typeDiffWeight = args
222:                                .getTypeDifferenceWeight(paramTypes);
223:                        // Choose this constructor if it represents the closest match.
224:                        if (typeDiffWeight < minTypeDiffWeight) {
225:                            constructorToUse = candidate;
226:                            argsToUse = args.arguments;
227:                            minTypeDiffWeight = typeDiffWeight;
228:                        }
229:                    }
230:
231:                    if (constructorToUse == null) {
232:                        throw new BeanCreationException(mbd
233:                                .getResourceDescription(), beanName,
234:                                "Could not resolve matching constructor");
235:                    }
236:
237:                    if (explicitArgs == null) {
238:                        mbd.resolvedConstructorOrFactoryMethod = constructorToUse;
239:                    }
240:                }
241:
242:                try {
243:                    Object beanInstance = this .instantiationStrategy
244:                            .instantiate(mbd, beanName, this .beanFactory,
245:                                    constructorToUse, argsToUse);
246:                    bw.setWrappedInstance(beanInstance);
247:                    return bw;
248:                } catch (Throwable ex) {
249:                    throw new BeanCreationException(mbd
250:                            .getResourceDescription(), beanName,
251:                            "Instantiation of bean failed", ex);
252:                }
253:            }
254:
255:            /**
256:             * Instantiate the bean using a named factory method. The method may be static, if the
257:             * bean definition parameter specifies a class, rather than a "factory-bean", or
258:             * an instance variable on a factory object itself configured using Dependency Injection.
259:             * <p>Implementation requires iterating over the static or instance methods with the
260:             * name specified in the RootBeanDefinition (the method may be overloaded) and trying
261:             * to match with the parameters. We don't have the types attached to constructor args,
262:             * so trial and error is the only way to go here. The explicitArgs array may contain
263:             * argument values passed in programmatically via the corresponding getBean method.
264:             * @param beanName the name of the bean
265:             * @param mbd the merged bean definition for the bean
266:             * @param explicitArgs argument values passed in programmatically via the getBean
267:             * method, or <code>null</code> if none (-> use constructor argument values from bean definition)
268:             * @return a BeanWrapper for the new instance
269:             */
270:            public BeanWrapper instantiateUsingFactoryMethod(String beanName,
271:                    RootBeanDefinition mbd, Object[] explicitArgs) {
272:                BeanWrapper bw = new BeanWrapperImpl();
273:                this .beanFactory.initBeanWrapper(bw);
274:
275:                Class factoryClass = null;
276:                Object factoryBean = null;
277:                boolean isStatic = true;
278:
279:                if (mbd.getFactoryBeanName() != null) {
280:                    factoryBean = this .beanFactory.getBean(mbd
281:                            .getFactoryBeanName());
282:                    factoryClass = factoryBean.getClass();
283:                    isStatic = false;
284:                } else {
285:                    // It's a static factory method on the bean class.
286:                    factoryClass = mbd.getBeanClass();
287:                }
288:
289:                Method factoryMethodToUse = null;
290:                Object[] argsToUse = null;
291:
292:                if (explicitArgs != null) {
293:                    argsToUse = explicitArgs;
294:                } else {
295:                    factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
296:                    if (factoryMethodToUse != null) {
297:                        // Found a cached factory method...
298:                        argsToUse = mbd.resolvedConstructorArguments;
299:                        if (argsToUse == null) {
300:                            Class[] paramTypes = factoryMethodToUse
301:                                    .getParameterTypes();
302:                            Object[] argsToResolve = mbd.preparedConstructorArguments;
303:                            TypeConverter converter = (this .typeConverter != null ? this .typeConverter
304:                                    : bw);
305:                            BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(
306:                                    this .beanFactory, beanName, mbd, converter);
307:                            argsToUse = new Object[argsToResolve.length];
308:                            for (int i = 0; i < argsToResolve.length; i++) {
309:                                Object argValue = argsToResolve[i];
310:                                if (argValue instanceof  AutowiredArgumentMarker) {
311:                                    argValue = resolveAutowiredArgument(
312:                                            new MethodParameter(
313:                                                    factoryMethodToUse, i),
314:                                            beanName, null, converter);
315:                                } else if (argValue instanceof  BeanMetadataElement) {
316:                                    argValue = valueResolver
317:                                            .resolveValueIfNecessary(
318:                                                    "factory method argument",
319:                                                    argValue);
320:                                }
321:                                argsToUse[i] = converter.convertIfNecessary(
322:                                        argValue, paramTypes[i],
323:                                        new MethodParameter(factoryMethodToUse,
324:                                                i));
325:                            }
326:                        }
327:                    }
328:                }
329:
330:                if (factoryMethodToUse == null) {
331:                    // Need to determine the factory method...
332:                    // Try all methods with this name to see if they match the given arguments.
333:                    Method[] candidates = ReflectionUtils
334:                            .getAllDeclaredMethods(factoryClass);
335:                    boolean autowiring = (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR);
336:                    int minTypeDiffWeight = Integer.MAX_VALUE;
337:                    ConstructorArgumentValues resolvedValues = null;
338:
339:                    int minNrOfArgs = 0;
340:                    if (explicitArgs != null) {
341:                        minNrOfArgs = explicitArgs.length;
342:                    } else {
343:                        // We don't have arguments passed in programmatically, so we need to resolve the
344:                        // arguments specified in the constructor arguments held in the bean definition.
345:                        ConstructorArgumentValues cargs = mbd
346:                                .getConstructorArgumentValues();
347:                        resolvedValues = new ConstructorArgumentValues();
348:                        minNrOfArgs = resolveConstructorArguments(beanName,
349:                                mbd, bw, cargs, resolvedValues);
350:                    }
351:
352:                    for (int i = 0; i < candidates.length; i++) {
353:                        Method candidate = candidates[i];
354:                        Class[] paramTypes = candidate.getParameterTypes();
355:
356:                        if (Modifier.isStatic(candidate.getModifiers()) == isStatic
357:                                && candidate.getName().equals(
358:                                        mbd.getFactoryMethodName())
359:                                && paramTypes.length >= minNrOfArgs) {
360:
361:                            ArgumentsHolder args = null;
362:
363:                            if (resolvedValues != null) {
364:                                // Resolved contructor arguments: type conversion and/or autowiring necessary.
365:                                try {
366:                                    args = createArgumentArray(beanName, mbd,
367:                                            resolvedValues, bw, paramTypes,
368:                                            candidate, autowiring);
369:                                } catch (UnsatisfiedDependencyException ex) {
370:                                    if (this .beanFactory.logger
371:                                            .isTraceEnabled()) {
372:                                        this .beanFactory.logger
373:                                                .trace("Ignoring factory method ["
374:                                                        + candidate
375:                                                        + "] of bean '"
376:                                                        + beanName + "': " + ex);
377:                                    }
378:                                    if (i == candidates.length - 1
379:                                            && factoryMethodToUse == null) {
380:                                        throw ex;
381:                                    } else {
382:                                        // Swallow and try next overloaded factory method.
383:                                        this .beanFactory
384:                                                .onSuppressedException(ex);
385:                                        continue;
386:                                    }
387:                                }
388:                            }
389:
390:                            else {
391:                                // Explicit arguments given -> arguments length must match exactly.
392:                                if (paramTypes.length != explicitArgs.length) {
393:                                    continue;
394:                                }
395:                                args = new ArgumentsHolder(explicitArgs);
396:                            }
397:
398:                            int typeDiffWeight = args
399:                                    .getTypeDifferenceWeight(paramTypes);
400:                            // Choose this constructor if it represents the closest match.
401:                            if (typeDiffWeight < minTypeDiffWeight) {
402:                                factoryMethodToUse = candidate;
403:                                argsToUse = args.arguments;
404:                                minTypeDiffWeight = typeDiffWeight;
405:                            }
406:                        }
407:                    }
408:
409:                    if (factoryMethodToUse == null) {
410:                        throw new BeanCreationException(
411:                                mbd.getResourceDescription(),
412:                                beanName,
413:                                "No matching factory method found: "
414:                                        + (mbd.getFactoryBeanName() != null ? "factory bean '"
415:                                                + mbd.getFactoryBeanName()
416:                                                + "'; "
417:                                                : "") + "factory method '"
418:                                        + mbd.getFactoryMethodName() + "'");
419:                    }
420:
421:                    if (explicitArgs == null) {
422:                        mbd.resolvedConstructorOrFactoryMethod = factoryMethodToUse;
423:                    }
424:                }
425:
426:                try {
427:                    Object beanInstance = this .instantiationStrategy
428:                            .instantiate(mbd, beanName, this .beanFactory,
429:                                    factoryBean, factoryMethodToUse, argsToUse);
430:                    if (beanInstance == null) {
431:                        return null;
432:                    }
433:                    bw.setWrappedInstance(beanInstance);
434:                    return bw;
435:                } catch (Throwable ex) {
436:                    throw new BeanCreationException(mbd
437:                            .getResourceDescription(), beanName,
438:                            "Instantiation of bean failed", ex);
439:                }
440:            }
441:
442:            /**
443:             * Resolve the constructor arguments for this bean into the resolvedValues object.
444:             * This may involve looking up other beans.
445:             * This method is also used for handling invocations of static factory methods.
446:             */
447:            private int resolveConstructorArguments(String beanName,
448:                    RootBeanDefinition mbd, BeanWrapper bw,
449:                    ConstructorArgumentValues cargs,
450:                    ConstructorArgumentValues resolvedValues) {
451:
452:                TypeConverter converterToUse = (this .typeConverter != null ? this .typeConverter
453:                        : bw);
454:                BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(
455:                        this .beanFactory, beanName, mbd, converterToUse);
456:
457:                int minNrOfArgs = cargs.getArgumentCount();
458:
459:                for (Iterator it = cargs.getIndexedArgumentValues().entrySet()
460:                        .iterator(); it.hasNext();) {
461:                    Map.Entry entry = (Map.Entry) it.next();
462:                    int index = ((Integer) entry.getKey()).intValue();
463:                    if (index < 0) {
464:                        throw new BeanCreationException(mbd
465:                                .getResourceDescription(), beanName,
466:                                "Invalid constructor argument index: " + index);
467:                    }
468:                    if (index > minNrOfArgs) {
469:                        minNrOfArgs = index + 1;
470:                    }
471:                    ConstructorArgumentValues.ValueHolder valueHolder = (ConstructorArgumentValues.ValueHolder) entry
472:                            .getValue();
473:                    if (valueHolder.isConverted()) {
474:                        resolvedValues.addIndexedArgumentValue(index,
475:                                valueHolder);
476:                    } else {
477:                        Object resolvedValue = valueResolver
478:                                .resolveValueIfNecessary(
479:                                        "constructor argument", valueHolder
480:                                                .getValue());
481:                        ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(
482:                                resolvedValue, valueHolder.getType());
483:                        resolvedValueHolder.setSource(valueHolder);
484:                        resolvedValues.addIndexedArgumentValue(index,
485:                                resolvedValueHolder);
486:                    }
487:                }
488:
489:                for (Iterator it = cargs.getGenericArgumentValues().iterator(); it
490:                        .hasNext();) {
491:                    ConstructorArgumentValues.ValueHolder valueHolder = (ConstructorArgumentValues.ValueHolder) it
492:                            .next();
493:                    if (valueHolder.isConverted()) {
494:                        resolvedValues.addGenericArgumentValue(valueHolder);
495:                    } else {
496:                        Object resolvedValue = valueResolver
497:                                .resolveValueIfNecessary(
498:                                        "constructor argument", valueHolder
499:                                                .getValue());
500:                        ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(
501:                                resolvedValue, valueHolder.getType());
502:                        resolvedValueHolder.setSource(valueHolder);
503:                        resolvedValues
504:                                .addGenericArgumentValue(resolvedValueHolder);
505:                    }
506:                }
507:
508:                return minNrOfArgs;
509:            }
510:
511:            /**
512:             * Create an array of arguments to invoke a constructor or factory method,
513:             * given the resolved constructor argument values.
514:             */
515:            private ArgumentsHolder createArgumentArray(String beanName,
516:                    RootBeanDefinition mbd,
517:                    ConstructorArgumentValues resolvedValues, BeanWrapper bw,
518:                    Class[] paramTypes, Object methodOrCtor, boolean autowiring)
519:                    throws UnsatisfiedDependencyException {
520:
521:                String methodType = (methodOrCtor instanceof  Constructor ? "constructor"
522:                        : "factory method");
523:                TypeConverter converter = (this .typeConverter != null ? this .typeConverter
524:                        : bw);
525:
526:                ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
527:                Set usedValueHolders = new HashSet(paramTypes.length);
528:                Set autowiredBeanNames = new LinkedHashSet(4);
529:                boolean resolveNecessary = false;
530:
531:                for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
532:                    Class paramType = paramTypes[paramIndex];
533:                    // Try to find matching constructor argument value, either indexed or generic.
534:                    ConstructorArgumentValues.ValueHolder valueHolder = resolvedValues
535:                            .getArgumentValue(paramIndex, paramType,
536:                                    usedValueHolders);
537:                    // If we couldn't find a direct match and are not supposed to autowire,
538:                    // let's try the next generic, untyped argument value as fallback:
539:                    // it could match after type conversion (for example, String -> int).
540:                    if (valueHolder == null && !autowiring) {
541:                        valueHolder = resolvedValues.getGenericArgumentValue(
542:                                null, usedValueHolders);
543:                    }
544:                    if (valueHolder != null) {
545:                        // We found a potential match - let's give it a try.
546:                        // Do not consider the same value definition multiple times!
547:                        usedValueHolders.add(valueHolder);
548:                        args.rawArguments[paramIndex] = valueHolder.getValue();
549:                        if (valueHolder.isConverted()) {
550:                            Object convertedValue = valueHolder
551:                                    .getConvertedValue();
552:                            args.arguments[paramIndex] = convertedValue;
553:                            args.preparedArguments[paramIndex] = convertedValue;
554:                        } else {
555:                            try {
556:                                Object originalValue = valueHolder.getValue();
557:                                Object convertedValue = converter
558:                                        .convertIfNecessary(
559:                                                originalValue,
560:                                                paramType,
561:                                                MethodParameter
562:                                                        .forMethodOrConstructor(
563:                                                                methodOrCtor,
564:                                                                paramIndex));
565:                                args.arguments[paramIndex] = convertedValue;
566:                                ConstructorArgumentValues.ValueHolder sourceHolder = (ConstructorArgumentValues.ValueHolder) valueHolder
567:                                        .getSource();
568:                                Object sourceValue = sourceHolder.getValue();
569:                                if (originalValue == sourceValue
570:                                        || sourceValue instanceof  TypedStringValue) {
571:                                    // Either a converted value or still the original one: store converted value.
572:                                    sourceHolder
573:                                            .setConvertedValue(convertedValue);
574:                                    args.preparedArguments[paramIndex] = convertedValue;
575:                                } else {
576:                                    resolveNecessary = true;
577:                                    args.preparedArguments[paramIndex] = sourceValue;
578:                                }
579:                            } catch (TypeMismatchException ex) {
580:                                throw new UnsatisfiedDependencyException(
581:                                        mbd.getResourceDescription(),
582:                                        beanName,
583:                                        paramIndex,
584:                                        paramType,
585:                                        "Could not convert "
586:                                                + methodType
587:                                                + " argument value of type ["
588:                                                + ObjectUtils
589:                                                        .nullSafeClassName(valueHolder
590:                                                                .getValue())
591:                                                + "] to required type ["
592:                                                + paramType.getName() + "]: "
593:                                                + ex.getMessage());
594:                            }
595:                        }
596:                    } else {
597:                        // No explicit match found: we're either supposed to autowire or
598:                        // have to fail creating an argument array for the given constructor.
599:                        if (!autowiring) {
600:                            throw new UnsatisfiedDependencyException(
601:                                    mbd.getResourceDescription(),
602:                                    beanName,
603:                                    paramIndex,
604:                                    paramType,
605:                                    "Ambiguous "
606:                                            + methodType
607:                                            + " argument types - "
608:                                            + "did you specify the correct bean references as "
609:                                            + methodType + " arguments?");
610:                        }
611:                        try {
612:                            MethodParameter param = MethodParameter
613:                                    .forMethodOrConstructor(methodOrCtor,
614:                                            paramIndex);
615:                            Object autowiredArgument = resolveAutowiredArgument(
616:                                    param, beanName, autowiredBeanNames,
617:                                    converter);
618:                            args.rawArguments[paramIndex] = autowiredArgument;
619:                            args.arguments[paramIndex] = autowiredArgument;
620:                            args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
621:                            resolveNecessary = true;
622:                        } catch (BeansException ex) {
623:                            throw new UnsatisfiedDependencyException(mbd
624:                                    .getResourceDescription(), beanName,
625:                                    paramIndex, paramType, ex.getMessage());
626:                        }
627:                    }
628:                }
629:
630:                for (Iterator it = autowiredBeanNames.iterator(); it.hasNext();) {
631:                    String autowiredBeanName = (String) it.next();
632:                    this .beanFactory.registerDependentBean(autowiredBeanName,
633:                            beanName);
634:                    if (this .beanFactory.logger.isDebugEnabled()) {
635:                        this .beanFactory.logger
636:                                .debug("Autowiring by type from bean name '"
637:                                        + beanName + "' via " + methodType
638:                                        + " to bean named '"
639:                                        + autowiredBeanName + "'");
640:                    }
641:                }
642:
643:                if (resolveNecessary) {
644:                    mbd.preparedConstructorArguments = args.preparedArguments;
645:                } else {
646:                    mbd.resolvedConstructorArguments = args.arguments;
647:                }
648:                mbd.constructorArgumentsResolved = true;
649:                return args;
650:            }
651:
652:            /**
653:             * Template method for resolving the specified argument which is supposed to be autowired.
654:             */
655:            protected abstract Object resolveAutowiredArgument(
656:                    MethodParameter param, String beanName,
657:                    Set autowiredBeanNames, TypeConverter typeConverter)
658:                    throws BeansException;
659:
660:            /**
661:             * Private inner class for holding argument combinations.
662:             */
663:            private static class ArgumentsHolder {
664:
665:                public Object rawArguments[];
666:
667:                public Object arguments[];
668:
669:                public Object preparedArguments[];
670:
671:                public ArgumentsHolder(int size) {
672:                    this .rawArguments = new Object[size];
673:                    this .arguments = new Object[size];
674:                    this .preparedArguments = new Object[size];
675:                }
676:
677:                public ArgumentsHolder(Object[] args) {
678:                    this .rawArguments = args;
679:                    this .arguments = args;
680:                    this .preparedArguments = args;
681:                }
682:
683:                public int getTypeDifferenceWeight(Class[] paramTypes) {
684:                    // If valid arguments found, determine type difference weight.
685:                    // Try type difference weight on both the converted arguments and
686:                    // the raw arguments. If the raw weight is better, use it.
687:                    // Decrease raw weight by 1024 to prefer it over equal converted weight.
688:                    int typeDiffWeight = AutowireUtils.getTypeDifferenceWeight(
689:                            paramTypes, this .arguments);
690:                    int rawTypeDiffWeight = AutowireUtils
691:                            .getTypeDifferenceWeight(paramTypes,
692:                                    this .rawArguments) - 1024;
693:                    return (rawTypeDiffWeight < typeDiffWeight ? rawTypeDiffWeight
694:                            : typeDiffWeight);
695:                }
696:            }
697:
698:            /**
699:             * Marker for autowired arguments in a cached argument array.
700:             */
701:            private static class AutowiredArgumentMarker {
702:            }
703:
704:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.