1 |
| |
2 |
| |
3 |
| |
4 |
| |
5 |
| |
6 |
| |
7 |
| |
8 |
| |
9 |
| |
10 |
| package org.picocontainer.defaults; |
11 |
| |
12 |
| import org.picocontainer.Parameter; |
13 |
| import org.picocontainer.PicoContainer; |
14 |
| import org.picocontainer.PicoInitializationException; |
15 |
| import org.picocontainer.PicoIntrospectionException; |
16 |
| |
17 |
| import java.lang.reflect.Constructor; |
18 |
| import java.lang.reflect.InvocationTargetException; |
19 |
| import java.lang.reflect.Method; |
20 |
| import java.util.ArrayList; |
21 |
| import java.util.Collections; |
22 |
| import java.util.HashSet; |
23 |
| import java.util.List; |
24 |
| import java.util.Set; |
25 |
| |
26 |
| |
27 |
| |
28 |
| |
29 |
| |
30 |
| |
31 |
| |
32 |
| |
33 |
| |
34 |
| |
35 |
| |
36 |
| |
37 |
| |
38 |
| |
39 |
| |
40 |
| public class SetterInjectionComponentAdapter extends InstantiatingComponentAdapter { |
41 |
| private transient Guard instantiationGuard; |
42 |
| private transient List setters; |
43 |
| private transient List setterNames; |
44 |
| private transient Class[] setterTypes; |
45 |
| |
46 |
| |
47 |
| |
48 |
| |
49 |
| |
50 |
20
| public SetterInjectionComponentAdapter(final Object componentKey,
|
51 |
| final Class componentImplementation, |
52 |
| Parameter[] parameters, |
53 |
| boolean allowNonPublicClasses) throws AssignabilityRegistrationException, NotConcreteRegistrationException { |
54 |
20
| super(componentKey, componentImplementation, parameters, allowNonPublicClasses);
|
55 |
| } |
56 |
| |
57 |
38
| public SetterInjectionComponentAdapter(final Object componentKey,
|
58 |
| final Class componentImplementation, |
59 |
| Parameter[] parameters) throws AssignabilityRegistrationException, NotConcreteRegistrationException { |
60 |
38
| super(componentKey, componentImplementation, parameters, false);
|
61 |
| } |
62 |
| |
63 |
0
| protected Constructor getGreediestSatisfiableConstructor(PicoContainer container) throws PicoIntrospectionException, UnsatisfiableDependenciesException, AmbiguousComponentResolutionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
|
64 |
0
| final Constructor constructor = getConstructor();
|
65 |
0
| getMatchingParameterListForSetters(container);
|
66 |
0
| return constructor;
|
67 |
| } |
68 |
| |
69 |
50
| private Constructor getConstructor() throws PicoInvocationTargetInitializationException {
|
70 |
50
| final Constructor constructor;
|
71 |
50
| try {
|
72 |
50
| constructor = getComponentImplementation().getConstructor(null);
|
73 |
| } catch (NoSuchMethodException e) { |
74 |
2
| throw new PicoInvocationTargetInitializationException(e);
|
75 |
| } catch (SecurityException e) { |
76 |
0
| throw new PicoInvocationTargetInitializationException(e);
|
77 |
| } |
78 |
| |
79 |
48
| return constructor;
|
80 |
| } |
81 |
| |
82 |
56
| private Parameter[] getMatchingParameterListForSetters(PicoContainer container) throws PicoInitializationException, UnsatisfiableDependenciesException {
|
83 |
56
| if (setters == null) {
|
84 |
48
| initializeSetterAndTypeLists();
|
85 |
| } |
86 |
| |
87 |
56
| final List matchingParameterList = new ArrayList(Collections.nCopies(setters.size(), null));
|
88 |
56
| final Set nonMatchingParameterPositions = new HashSet();
|
89 |
56
| final Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(setterTypes);
|
90 |
56
| for (int i = 0; i < currentParameters.length; i++) {
|
91 |
66
| final Parameter parameter = currentParameters[i];
|
92 |
66
| boolean failedDependency = true;
|
93 |
66
| for (int j = 0; j < setterTypes.length; j++) {
|
94 |
88
| if (matchingParameterList.get(j) == null && parameter.isResolvable(container, this, setterTypes[j])) {
|
95 |
62
| matchingParameterList.set(j, parameter);
|
96 |
62
| failedDependency = false;
|
97 |
62
| break;
|
98 |
| } |
99 |
| } |
100 |
66
| if (failedDependency) {
|
101 |
4
| nonMatchingParameterPositions.add(new Integer(i));
|
102 |
| } |
103 |
| } |
104 |
| |
105 |
56
| final Set unsatisfiableDependencyTypes = new HashSet();
|
106 |
56
| for (int i = 0; i < matchingParameterList.size(); i++) {
|
107 |
70
| if (matchingParameterList.get(i) == null) {
|
108 |
8
| unsatisfiableDependencyTypes.add(setterTypes[i]);
|
109 |
| } |
110 |
| } |
111 |
56
| if (unsatisfiableDependencyTypes.size() > 0) {
|
112 |
6
| throw new UnsatisfiableDependenciesException(this, unsatisfiableDependencyTypes);
|
113 |
50
| } else if (nonMatchingParameterPositions.size() > 0) {
|
114 |
0
| throw new PicoInitializationException("Following parameters do not match any of the setters for "
|
115 |
| + getComponentImplementation() + ": " + nonMatchingParameterPositions.toString()); |
116 |
| } |
117 |
50
| return (Parameter[]) matchingParameterList.toArray(new Parameter[matchingParameterList.size()]);
|
118 |
| } |
119 |
| |
120 |
50
| public Object getComponentInstance(final PicoContainer container) throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
|
121 |
50
| final Constructor constructor = getConstructor();
|
122 |
48
| if (instantiationGuard == null) {
|
123 |
40
| instantiationGuard = new Guard() {
|
124 |
46
| public Object run() {
|
125 |
46
| final Parameter[] matchingParameters = getMatchingParameterListForSetters(guardedContainer);
|
126 |
42
| try {
|
127 |
42
| final Object componentInstance = newInstance(constructor, null);
|
128 |
36
| for (int i = 0; i < setters.size(); i++) {
|
129 |
38
| final Method setter = (Method) setters.get(i);
|
130 |
38
| setter.invoke(componentInstance, new Object[]{matchingParameters[i].resolveInstance(guardedContainer, SetterInjectionComponentAdapter.this, setterTypes[i])});
|
131 |
| } |
132 |
32
| return componentInstance;
|
133 |
| } catch (InvocationTargetException e) { |
134 |
6
| if (e.getTargetException() instanceof RuntimeException) {
|
135 |
2
| throw (RuntimeException) e.getTargetException();
|
136 |
4
| } else if (e.getTargetException() instanceof Error) {
|
137 |
2
| throw (Error) e.getTargetException();
|
138 |
| } |
139 |
2
| throw new PicoInvocationTargetInitializationException(e.getTargetException());
|
140 |
| } catch (InstantiationException e) { |
141 |
0
| throw new PicoInvocationTargetInitializationException(e);
|
142 |
| } catch (IllegalAccessException e) { |
143 |
0
| throw new PicoInvocationTargetInitializationException(e);
|
144 |
| } |
145 |
| } |
146 |
| }; |
147 |
| } |
148 |
48
| instantiationGuard.setArguments(container);
|
149 |
48
| return instantiationGuard.observe(getComponentImplementation());
|
150 |
| } |
151 |
| |
152 |
12
| public void verify(final PicoContainer container) throws PicoIntrospectionException {
|
153 |
12
| if (verifyingGuard == null) {
|
154 |
10
| verifyingGuard = new Guard() {
|
155 |
10
| public Object run() {
|
156 |
10
| final Parameter[] currentParameters = getMatchingParameterListForSetters(guardedContainer);
|
157 |
8
| for (int i = 0; i < currentParameters.length; i++) {
|
158 |
8
| currentParameters[i].verify(container, SetterInjectionComponentAdapter.this, setterTypes[i]);
|
159 |
| } |
160 |
4
| return null;
|
161 |
| } |
162 |
| }; |
163 |
| } |
164 |
12
| verifyingGuard.setArguments(container);
|
165 |
12
| verifyingGuard.observe(getComponentImplementation());
|
166 |
| } |
167 |
| |
168 |
48
| private void initializeSetterAndTypeLists() {
|
169 |
48
| setters = new ArrayList();
|
170 |
48
| setterNames = new ArrayList();
|
171 |
48
| final List typeList = new ArrayList();
|
172 |
48
| final Method[] methods = getComponentImplementation().getMethods();
|
173 |
48
| for (int i = 0; i < methods.length; i++) {
|
174 |
562
| final Method method = methods[i];
|
175 |
562
| final Class[] parameterTypes = method.getParameterTypes();
|
176 |
| |
177 |
562
| if (parameterTypes.length == 1) {
|
178 |
158
| String methodName = method.getName();
|
179 |
158
| boolean isBeanStyle = methodName.length() >= 4 && methodName.startsWith("set") && Character.isUpperCase(methodName.charAt(3));
|
180 |
158
| if (isBeanStyle) {
|
181 |
62
| String attribute = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
|
182 |
62
| setters.add(method);
|
183 |
62
| setterNames.add(attribute);
|
184 |
62
| typeList.add(parameterTypes[0]);
|
185 |
| } |
186 |
| } |
187 |
| } |
188 |
48
| setterTypes = (Class[]) typeList.toArray(new Class[0]);
|
189 |
| } |
190 |
| } |