1 |
| |
2 |
| |
3 |
| |
4 |
| |
5 |
| |
6 |
| |
7 |
| |
8 |
| |
9 |
| |
10 |
| |
11 |
| package org.picocontainer.defaults; |
12 |
| |
13 |
| import org.picocontainer.Parameter; |
14 |
| import org.picocontainer.PicoContainer; |
15 |
| import org.picocontainer.PicoInitializationException; |
16 |
| import org.picocontainer.PicoIntrospectionException; |
17 |
| |
18 |
| import java.lang.reflect.Constructor; |
19 |
| import java.lang.reflect.InvocationTargetException; |
20 |
| import java.lang.reflect.Modifier; |
21 |
| import java.util.ArrayList; |
22 |
| import java.util.Arrays; |
23 |
| import java.util.Collections; |
24 |
| import java.util.Comparator; |
25 |
| import java.util.HashSet; |
26 |
| import java.util.List; |
27 |
| import java.util.Set; |
28 |
| |
29 |
| |
30 |
| |
31 |
| |
32 |
| |
33 |
| |
34 |
| |
35 |
| |
36 |
| |
37 |
| |
38 |
| |
39 |
| |
40 |
| |
41 |
| |
42 |
| |
43 |
| public class ConstructorInjectionComponentAdapter extends InstantiatingComponentAdapter { |
44 |
| private transient List sortedMatchingConstructors; |
45 |
| private transient Guard instantiationGuard; |
46 |
| private ComponentMonitor componentMonitor; |
47 |
| |
48 |
| private static abstract class Guard extends ThreadLocalCyclicDependencyGuard { |
49 |
| protected PicoContainer guardedContainer; |
50 |
| |
51 |
970
| private void setArguments(PicoContainer container) {
|
52 |
970
| this.guardedContainer = container;
|
53 |
| } |
54 |
| } |
55 |
| |
56 |
| |
57 |
| |
58 |
| |
59 |
| |
60 |
1146
| public ConstructorInjectionComponentAdapter(final Object componentKey,
|
61 |
| final Class componentImplementation, |
62 |
| Parameter[] parameters, |
63 |
| boolean allowNonPublicClasses, |
64 |
| ComponentMonitor componentMonitor) throws AssignabilityRegistrationException, NotConcreteRegistrationException { |
65 |
1146
| super(componentKey, componentImplementation, parameters, allowNonPublicClasses);
|
66 |
1146
| this.componentMonitor = componentMonitor;
|
67 |
| } |
68 |
| |
69 |
130
| public ConstructorInjectionComponentAdapter(Object componentKey, Class componentImplementation, Parameter[] parameters) {
|
70 |
130
| this(componentKey, componentImplementation, parameters, false, NullComponentMonitor.getInstance());
|
71 |
| } |
72 |
| |
73 |
| |
74 |
| |
75 |
| |
76 |
114
| public ConstructorInjectionComponentAdapter(Object componentKey,
|
77 |
| Class componentImplementation) throws AssignabilityRegistrationException, NotConcreteRegistrationException { |
78 |
114
| this(componentKey, componentImplementation, null);
|
79 |
| } |
80 |
| |
81 |
1018
| protected Constructor getGreediestSatisfiableConstructor(PicoContainer container) throws PicoIntrospectionException, UnsatisfiableDependenciesException, AmbiguousComponentResolutionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
|
82 |
1018
| Constructor greediestConstructor = null;
|
83 |
1018
| final Set conflicts = new HashSet();
|
84 |
1018
| final Set unsatisfiableDependencyTypes = new HashSet();
|
85 |
1018
| if (sortedMatchingConstructors == null) {
|
86 |
848
| sortedMatchingConstructors = getSortedMatchingConstructors();
|
87 |
| } |
88 |
1018
| int lastSatisfiableConstructorSize = -1;
|
89 |
1018
| for (int i = 0; i < sortedMatchingConstructors.size(); i++) {
|
90 |
2040
| boolean failedDependency = false;
|
91 |
2040
| Constructor constructor = (Constructor) sortedMatchingConstructors.get(i);
|
92 |
2040
| Class[] parameterTypes = constructor.getParameterTypes();
|
93 |
2040
| Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
|
94 |
| |
95 |
| |
96 |
2040
| for (int j = 0; j < currentParameters.length; j++) {
|
97 |
| |
98 |
1762
| if (currentParameters[j].isResolvable(container, this, parameterTypes[j])) {
|
99 |
670
| continue;
|
100 |
| } |
101 |
1078
| unsatisfiableDependencyTypes.add(Arrays.asList(parameterTypes));
|
102 |
1078
| failedDependency = true;
|
103 |
1078
| break;
|
104 |
| } |
105 |
| |
106 |
2026
| if (greediestConstructor != null && parameterTypes.length != lastSatisfiableConstructorSize) {
|
107 |
16
| if (conflicts.isEmpty()) {
|
108 |
| |
109 |
14
| return greediestConstructor;
|
110 |
| } else { |
111 |
| |
112 |
2
| conflicts.add(constructor);
|
113 |
| } |
114 |
2010
| } else if (!failedDependency && lastSatisfiableConstructorSize == parameterTypes.length) {
|
115 |
| |
116 |
2
| conflicts.add(constructor);
|
117 |
2
| conflicts.add(greediestConstructor);
|
118 |
2008
| } else if (!failedDependency) {
|
119 |
930
| greediestConstructor = constructor;
|
120 |
930
| lastSatisfiableConstructorSize = parameterTypes.length;
|
121 |
| } |
122 |
| } |
123 |
990
| if (!conflicts.isEmpty()) {
|
124 |
2
| throw new TooManySatisfiableConstructorsException(getComponentImplementation(), conflicts);
|
125 |
988
| } else if (greediestConstructor == null && !unsatisfiableDependencyTypes.isEmpty()) {
|
126 |
72
| throw new UnsatisfiableDependenciesException(this, unsatisfiableDependencyTypes);
|
127 |
916
| } else if (greediestConstructor == null) {
|
128 |
| |
129 |
2
| final Set nonMatching = new HashSet();
|
130 |
2
| final Constructor[] constructors = getComponentImplementation().getDeclaredConstructors();
|
131 |
2
| for (int i = 0; i < constructors.length; i++) {
|
132 |
2
| nonMatching.add(constructors[i]);
|
133 |
| } |
134 |
2
| throw new PicoInitializationException("Either do the specified parameters not match any of the following constructors: " + nonMatching.toString() + " or the constructors were not accessible for '" + getComponentImplementation() + "'");
|
135 |
| } |
136 |
914
| return greediestConstructor;
|
137 |
| } |
138 |
| |
139 |
970
| public Object getComponentInstance(PicoContainer container) throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
|
140 |
970
| if (instantiationGuard == null) {
|
141 |
802
| instantiationGuard = new Guard() {
|
142 |
956
| public Object run() {
|
143 |
956
| final Constructor constructor;
|
144 |
956
| try {
|
145 |
956
| constructor = getGreediestSatisfiableConstructor(guardedContainer);
|
146 |
| } catch (AmbiguousComponentResolutionException e) { |
147 |
14
| e.setComponent(getComponentImplementation());
|
148 |
14
| throw e;
|
149 |
| } |
150 |
894
| try {
|
151 |
894
| Object[] parameters = getConstructorArguments(guardedContainer, constructor);
|
152 |
864
| componentMonitor.instantiating(constructor);
|
153 |
864
| long startTime = System.currentTimeMillis();
|
154 |
864
| Object inst = newInstance(constructor, parameters);
|
155 |
854
| componentMonitor.instantiated(constructor, startTime, System.currentTimeMillis() - startTime);
|
156 |
854
| return inst;
|
157 |
| } catch (InvocationTargetException e) { |
158 |
10
| componentMonitor.instantiationFailed(constructor, e);
|
159 |
10
| if (e.getTargetException() instanceof RuntimeException) {
|
160 |
4
| throw (RuntimeException) e.getTargetException();
|
161 |
6
| } else if (e.getTargetException() instanceof Error) {
|
162 |
2
| throw (Error) e.getTargetException();
|
163 |
| } |
164 |
4
| throw new PicoInvocationTargetInitializationException(e.getTargetException());
|
165 |
| } catch (InstantiationException e) { |
166 |
| |
167 |
| |
168 |
| componentMonitor.instantiationFailed(constructor, e); |
169 |
| throw new PicoInitializationException("Should never get here"); |
170 |
| |
171 |
| } catch (IllegalAccessException e) { |
172 |
| |
173 |
| |
174 |
| componentMonitor.instantiationFailed(constructor, e); |
175 |
| throw new PicoInitializationException(e); |
176 |
| |
177 |
| } |
178 |
| } |
179 |
| }; |
180 |
| } |
181 |
970
| instantiationGuard.setArguments(container);
|
182 |
970
| return instantiationGuard.observe(getComponentImplementation());
|
183 |
| } |
184 |
| |
185 |
894
| protected Object[] getConstructorArguments(PicoContainer container, Constructor ctor) {
|
186 |
894
| Class[] parameterTypes = ctor.getParameterTypes();
|
187 |
894
| Object[] result = new Object[parameterTypes.length];
|
188 |
894
| Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
|
189 |
| |
190 |
894
| for (int i = 0; i < currentParameters.length; i++) {
|
191 |
570
| result[i] = currentParameters[i].resolveInstance(container, this, parameterTypes[i]);
|
192 |
| } |
193 |
864
| return result;
|
194 |
| } |
195 |
| |
196 |
848
| private List getSortedMatchingConstructors() {
|
197 |
848
| List matchingConstructors = new ArrayList();
|
198 |
848
| Constructor[] allConstructors = getComponentImplementation().getDeclaredConstructors();
|
199 |
| |
200 |
848
| Constructor constructor;
|
201 |
848
| for (int i = 0; i < allConstructors.length; i++) {
|
202 |
1348
| constructor = allConstructors[i];
|
203 |
1348
| if ((parameters == null || constructor.getParameterTypes().length == parameters.length)
|
204 |
| && (allowNonPublicClasses || (constructor.getModifiers() & Modifier.PUBLIC) != 0)) { |
205 |
1242
| matchingConstructors.add(constructor);
|
206 |
| } |
207 |
| } |
208 |
| |
209 |
848
| if (parameters == null) {
|
210 |
722
| Collections.sort(matchingConstructors, new Comparator() {
|
211 |
780
| public int compare(Object arg0, Object arg1) {
|
212 |
780
| return ((Constructor) arg1).getParameterTypes().length - ((Constructor) arg0).getParameterTypes().length;
|
213 |
| } |
214 |
| }); |
215 |
| } |
216 |
848
| return matchingConstructors;
|
217 |
| } |
218 |
| } |