1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
package org.apache.commons.inject.impl.bind; |
18 | |
|
19 | |
import java.lang.annotation.Annotation; |
20 | |
import java.lang.reflect.Constructor; |
21 | |
import java.lang.reflect.Method; |
22 | |
import java.lang.reflect.Modifier; |
23 | |
import java.util.List; |
24 | |
|
25 | |
import org.apache.commons.inject.api.IBinding; |
26 | |
import org.apache.commons.inject.api.IInjector; |
27 | |
import org.apache.commons.inject.api.IKey; |
28 | |
import org.apache.commons.inject.api.IPoint; |
29 | |
import org.apache.commons.inject.api.IProvider; |
30 | |
import org.apache.commons.inject.api.Key; |
31 | |
import org.apache.commons.inject.api.bind.IAnnotatedBindingBuilder; |
32 | |
import org.apache.commons.inject.api.bind.ILinkedBindingBuilder; |
33 | |
import org.apache.commons.inject.api.bind.IScopedBindingBuilder; |
34 | |
import org.apache.commons.inject.api.bind.Scopes; |
35 | |
import org.apache.commons.inject.api.bind.IBinder.IInjectionListener; |
36 | |
import org.apache.commons.inject.api.bind.IBinder.IInjectionParticipator; |
37 | |
import org.apache.commons.inject.impl.AbstractBaseProvider; |
38 | |
import org.apache.commons.inject.impl.AbstractScopedProvider; |
39 | |
import org.apache.commons.inject.impl.Introspector; |
40 | |
import org.apache.commons.inject.impl.ListPoint; |
41 | |
import org.apache.commons.inject.impl.MutableBindingSet; |
42 | |
import org.apache.commons.inject.impl.AbstractBindingSet.MappedKey; |
43 | |
|
44 | |
import com.google.inject.Provider; |
45 | |
|
46 | |
|
47 | |
|
48 | |
|
49 | |
|
50 | |
|
51 | |
|
52 | |
|
53 | 8 | public class DefaultBindingBuilder<T> implements IAnnotatedBindingBuilder<T> { |
54 | |
private final Class<T> sourceType; |
55 | |
private final IKey<T> sourceKey; |
56 | |
private Annotation sourceAnnotation; |
57 | |
private Class<? extends Annotation> sourceAnnotationType; |
58 | |
private T targetInstance; |
59 | |
private Class<? extends T> targetType; |
60 | |
private Constructor<? extends T> targetConstructor; |
61 | |
private Method targetMethod; |
62 | |
private Provider<? extends T> targetProvider; |
63 | |
private IProvider<? extends T> targetIProvider; |
64 | |
private Scopes scope; |
65 | |
|
66 | |
public DefaultBindingBuilder(Class<T> pType) { |
67 | 20 | this(pType, Key.NO_NAME); |
68 | 20 | } |
69 | |
|
70 | 36 | public DefaultBindingBuilder(Class<T> pType, String pName) { |
71 | 36 | sourceKey = new Key<T>(pType, pName); |
72 | 36 | sourceType = pType; |
73 | 36 | } |
74 | |
|
75 | 0 | public DefaultBindingBuilder(IKey<T> pKey) { |
76 | 0 | sourceKey = pKey; |
77 | 0 | sourceType = null; |
78 | 0 | } |
79 | |
|
80 | |
@Override |
81 | |
public void toInstance(T pInstance) { |
82 | 8 | if (pInstance == null) { |
83 | 0 | throw new NullPointerException("The target instance must not be null."); |
84 | |
} |
85 | 8 | checkNoTarget(); |
86 | 8 | targetInstance = pInstance; |
87 | 8 | asEagerSingleton(); |
88 | 8 | } |
89 | |
|
90 | |
private void checkNoTarget() { |
91 | 19 | if (targetInstance != null |
92 | |
|| targetType != null |
93 | |
|| targetConstructor != null |
94 | |
|| targetMethod != null |
95 | |
|| targetProvider != null |
96 | |
|| targetIProvider != null) { |
97 | 0 | throw new IllegalStateException("The methods " + TARGET_METHOD_LIST |
98 | |
+ " are mutually exclusive, and may be invoked only once."); |
99 | |
} |
100 | 19 | } |
101 | |
|
102 | |
private static final String SCOPE_METHOD_LIST |
103 | |
= "toInstance(Object), scope(Scopes), asEagerSingleton(), and asLazySingleton()"; |
104 | |
private static final String TARGET_METHOD_LIST |
105 | |
= "toInstance(Object), to(Class), to(Constructor), to(Method)," |
106 | |
+ " to(Provider, Class), to(IProvider)"; |
107 | |
|
108 | |
@Override |
109 | |
public IScopedBindingBuilder<T> to(Class<? extends T> pImplClass) { |
110 | 11 | if (pImplClass == null) { |
111 | 0 | throw new NullPointerException("The target class must not be null."); |
112 | |
} |
113 | 11 | checkNoTarget(); |
114 | 11 | targetType = pImplClass; |
115 | 11 | return this; |
116 | |
} |
117 | |
|
118 | |
@Override |
119 | |
public IScopedBindingBuilder<T> to(Constructor<? extends T> pConstructor) { |
120 | 0 | if (pConstructor == null) { |
121 | 0 | throw new NullPointerException("The target constructor must not be null."); |
122 | |
} |
123 | 0 | checkNoTarget(); |
124 | 0 | targetConstructor = pConstructor; |
125 | 0 | return this; |
126 | |
} |
127 | |
|
128 | |
@Override |
129 | |
public IScopedBindingBuilder<T> to(Method pFactoryMethod) { |
130 | 0 | if (pFactoryMethod == null) { |
131 | 0 | throw new NullPointerException("The target constructor must not be null."); |
132 | |
} |
133 | 0 | if (!Modifier.isStatic(pFactoryMethod.getModifiers())) { |
134 | 0 | throw new IllegalStateException("The target method must be static."); |
135 | |
} |
136 | 0 | if (pFactoryMethod.getReturnType().isPrimitive()) { |
137 | 0 | throw new IllegalStateException("The target method must return a non-primitive result."); |
138 | |
} |
139 | 0 | if (pFactoryMethod.getReturnType().isArray()) { |
140 | 0 | throw new IllegalStateException("The target method must return a single object, and not an array."); |
141 | |
} |
142 | 0 | if (Void.TYPE == pFactoryMethod.getReturnType()) { |
143 | 0 | throw new IllegalStateException("The target method must return a non-void result."); |
144 | |
} |
145 | 0 | checkNoTarget(); |
146 | 0 | targetMethod = pFactoryMethod; |
147 | 0 | return this; |
148 | |
} |
149 | |
|
150 | |
@Override |
151 | |
public <S extends T> IScopedBindingBuilder<T> to(Class<S> pType, |
152 | |
Provider<S> pProvider) { |
153 | 0 | if (pType == null) { |
154 | 0 | throw new NullPointerException("The target type must not be null."); |
155 | |
} |
156 | 0 | if (pProvider == null) { |
157 | 0 | throw new NullPointerException("The target provider must not be null."); |
158 | |
} |
159 | 0 | checkNoTarget(); |
160 | 0 | targetType = pType; |
161 | 0 | targetProvider = pProvider; |
162 | 0 | return this; |
163 | |
} |
164 | |
|
165 | |
@Override |
166 | |
public IScopedBindingBuilder<T> to(IProvider<? extends T> pProvider) { |
167 | 0 | if (pProvider == null) { |
168 | 0 | throw new NullPointerException("The target provider must not be null."); |
169 | |
} |
170 | 0 | checkNoTarget(); |
171 | 0 | targetIProvider = pProvider; |
172 | 0 | return this; |
173 | |
} |
174 | |
|
175 | |
@Override |
176 | |
public void scope(Scopes pScope) { |
177 | 36 | if (pScope == null) { |
178 | 0 | throw new NullPointerException("The target scope must not be null."); |
179 | |
} |
180 | 36 | if (scope != null) { |
181 | 0 | throw new IllegalStateException("The methods " + SCOPE_METHOD_LIST |
182 | |
+ " are mutually exclusive, and may be invoked only once."); |
183 | |
} |
184 | 36 | scope = pScope; |
185 | 36 | } |
186 | |
|
187 | |
@Override |
188 | |
public void asEagerSingleton() { |
189 | 11 | scope(Scopes.EAGER_SINGLETON); |
190 | 11 | } |
191 | |
|
192 | |
@Override |
193 | |
public void asLazySingleton() { |
194 | 3 | scope(Scopes.LAZY_SINGLETON); |
195 | 3 | } |
196 | |
|
197 | |
@Override |
198 | |
public ILinkedBindingBuilder<T> annotatedWith(Annotation pAnnotation) { |
199 | 0 | if (pAnnotation == null) { |
200 | 0 | throw new NullPointerException("The annotation must not be null."); |
201 | |
} |
202 | 0 | if (sourceAnnotation != null) { |
203 | 0 | throw new IllegalStateException("The method annotatedWith(Annotation) must not be invoked twice."); |
204 | |
} |
205 | 0 | sourceAnnotation = pAnnotation; |
206 | 0 | return this; |
207 | |
} |
208 | |
|
209 | |
@Override |
210 | |
public ILinkedBindingBuilder<T> annotatedWith( |
211 | |
Class<? extends Annotation> pAnnotationType) { |
212 | 2 | if (pAnnotationType == null) { |
213 | 0 | throw new NullPointerException("The annotation type must not be null."); |
214 | |
} |
215 | 2 | if (sourceAnnotationType != null) { |
216 | 0 | throw new IllegalStateException("The method annotatedWith(Class) must not be invoked twice."); |
217 | |
} |
218 | 2 | sourceAnnotationType = pAnnotationType; |
219 | 2 | return this; |
220 | |
} |
221 | |
|
222 | |
public void build(MutableBindingSet pBindings, final List<IInjectionListener> pListeners, |
223 | |
final List<IInjectionParticipator> pParticipators) { |
224 | 36 | final Class<T> baseType = getBaseType(); |
225 | 36 | ListPoint<T> point = Introspector.getInstance().getPoint(baseType, pBindings); |
226 | 36 | final IKey<T> key = sourceKey; |
227 | 36 | if (pParticipators != null) { |
228 | 36 | for (IInjectionParticipator participator : pParticipators) { |
229 | 2 | final List<IPoint<Object>> points = participator.getPoints(key, baseType); |
230 | 2 | if (points != null) { |
231 | 2 | for (IPoint<Object> p : points) { |
232 | |
@SuppressWarnings("unchecked") |
233 | 1 | final IPoint<T> pnt = (IPoint<T>) p; |
234 | 1 | point.add(pnt); |
235 | 1 | } |
236 | |
} |
237 | 2 | } |
238 | |
} |
239 | 36 | if (pListeners != null && !pListeners.isEmpty()) { |
240 | 9 | point.add(new IPoint<T>(){ |
241 | |
@Override |
242 | |
public void injectTo(T pInstance, IInjector pInjector) { |
243 | 11 | for (IInjectionListener listener : pListeners) { |
244 | 11 | listener.initialized(key, pInstance); |
245 | |
} |
246 | 11 | } |
247 | |
}); |
248 | |
} |
249 | 36 | final IProvider<T> baseProvider = getBaseProvider(baseType, point, pBindings); |
250 | 36 | final IProvider<T> scopedProvider = getScopedProvider(baseProvider); |
251 | 36 | final IBinding<T> binding = new DefaultBinding<T>(scopedProvider, point); |
252 | |
final Annotation[] annotations; |
253 | 36 | if (sourceAnnotation == null) { |
254 | 36 | annotations = Key.NO_ANNOTATIONS; |
255 | |
} else { |
256 | 0 | annotations = new Annotation[]{ sourceAnnotation }; |
257 | |
} |
258 | 36 | final MappedKey<T> mkey = new MappedKey<T>(sourceKey.getType(), sourceKey.getName(), |
259 | |
annotations, sourceAnnotationType); |
260 | |
|
261 | 36 | pBindings.add(mkey, binding); |
262 | 36 | } |
263 | |
|
264 | |
private Class<T> getBaseType() { |
265 | 36 | if (targetInstance != null) { |
266 | |
@SuppressWarnings("unchecked") |
267 | 8 | final Class<T> cl = (Class<T>) targetInstance.getClass(); |
268 | 8 | return cl; |
269 | |
} |
270 | 28 | if (targetProvider != null) { |
271 | |
@SuppressWarnings("unchecked") |
272 | 0 | final Class<T> cl = (Class<T>) targetType; |
273 | 0 | return cl; |
274 | |
} |
275 | 28 | if (targetIProvider != null) { |
276 | |
@SuppressWarnings("unchecked") |
277 | 0 | final Class<T> cl = (Class<T>) targetIProvider.getType(); |
278 | 0 | return cl; |
279 | |
} |
280 | 28 | if (targetType != null) { |
281 | |
@SuppressWarnings("unchecked") |
282 | 11 | final Class<T> cl = (Class<T>) targetType; |
283 | 11 | return cl; |
284 | |
} |
285 | 17 | if (targetConstructor != null) { |
286 | |
@SuppressWarnings("unchecked") |
287 | 0 | final Class<T> cl = (Class<T>) targetConstructor.getDeclaringClass(); |
288 | 0 | return cl; |
289 | |
} |
290 | 17 | if (targetMethod != null) { |
291 | |
@SuppressWarnings("unchecked") |
292 | 0 | final Class<T> cl = (Class<T>) targetMethod.getReturnType(); |
293 | 0 | return cl; |
294 | |
} |
295 | 17 | if (sourceType == null) { |
296 | 0 | throw new IllegalStateException("Neither of the methods " |
297 | |
+ TARGET_METHOD_LIST + " has been invoked on this binding builder," |
298 | |
+ " which is required when binding a key."); |
299 | |
} |
300 | 17 | if (sourceType.isInterface() || Modifier.isAbstract(sourceType.getModifiers())) { |
301 | 0 | throw new IllegalStateException("Neither of the methods " |
302 | |
+ TARGET_METHOD_LIST + " has been invoked on this binding builder, " |
303 | |
+ " but cannot bind " + sourceType.getName() |
304 | |
+ " as target type, because it is an interface, or an abstract class."); |
305 | |
} |
306 | 17 | return sourceType; |
307 | |
} |
308 | |
private AbstractBaseProvider<T> getBaseProvider(Class<T> pType, IPoint<T> pPoint, MutableBindingSet pBindings) { |
309 | 36 | if (targetInstance != null) { |
310 | 8 | return new AbstractBaseProvider<T>(pType, pPoint){ |
311 | |
@Override |
312 | |
public T get() { |
313 | 8 | return targetInstance; |
314 | |
} |
315 | |
}; |
316 | |
} |
317 | 28 | if (targetProvider != null) { |
318 | 0 | return new AbstractBaseProvider<T>(pType, pPoint){ |
319 | |
@Override |
320 | |
public T get() { |
321 | 0 | return (T) targetProvider.get(); |
322 | |
} |
323 | |
}; |
324 | |
} |
325 | 28 | if (targetIProvider != null) { |
326 | 0 | return new AbstractBaseProvider<T>(pType, pPoint){ |
327 | |
@Override |
328 | |
public T get() { |
329 | 0 | return (T) targetIProvider.get(); |
330 | |
} |
331 | |
|
332 | |
}; |
333 | |
} |
334 | 28 | if (targetType != null) { |
335 | |
@SuppressWarnings("unchecked") |
336 | 11 | final Class<T> cl = (Class<T>) targetType; |
337 | 11 | final AbstractBaseProvider<T> abp = (AbstractBaseProvider<T>) Introspector.getInstance().getProvider(cl, pPoint, pBindings); |
338 | 11 | return abp; |
339 | |
} |
340 | 17 | if (targetConstructor != null) { |
341 | 0 | final AbstractBaseProvider<T> abp = (AbstractBaseProvider<T>) Introspector.getInstance().getProvider(targetConstructor, pBindings); |
342 | 0 | return abp; |
343 | |
} |
344 | 17 | if (targetMethod != null) { |
345 | |
@SuppressWarnings("unchecked") |
346 | 0 | final AbstractBaseProvider<T> abp = (AbstractBaseProvider<T>) Introspector.getInstance().getProvider(targetMethod, pBindings); |
347 | 0 | return abp; |
348 | |
} |
349 | 17 | if (sourceType != null) { |
350 | 17 | final AbstractBaseProvider<T> abp = (AbstractBaseProvider<T>) Introspector.getInstance().getProvider(sourceType, pPoint, pBindings); |
351 | 17 | return abp; |
352 | |
} |
353 | 0 | throw new IllegalStateException("Neither of the methods " |
354 | |
+ TARGET_METHOD_LIST + " has been invoked on this binding builder."); |
355 | |
} |
356 | |
|
357 | |
public AbstractScopedProvider<T> getScopedProvider(IProvider<T> pBaseProvider) { |
358 | 36 | if (scope == null) { |
359 | 0 | throw new IllegalStateException("Neither of the methods " |
360 | |
+ SCOPE_METHOD_LIST + " has been invoked on this binding builder."); |
361 | |
|
362 | |
} |
363 | 36 | switch(scope) { |
364 | |
case PER_CALL: |
365 | 22 | return new PerCallProvider<T>(pBaseProvider); |
366 | |
case EAGER_SINGLETON: |
367 | 11 | return new EagerSingletonProvider<T>(pBaseProvider); |
368 | |
case LAZY_SINGLETON: |
369 | 3 | return new LazySingletonProvider<T>(pBaseProvider); |
370 | |
default: |
371 | 0 | throw new IllegalStateException("Invalid scope: " + scope); |
372 | |
} |
373 | |
} |
374 | |
} |