/core/test/com/google/inject/InjectorTest.java
Java | 413 lines | 314 code | 80 blank | 19 comment | 1 complexity | a4a5a3766cfdb6525c862f3bc88d468d MD5 | raw file
1/**
2 * Copyright (C) 2006 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.inject;
18
19import static com.google.inject.Asserts.assertContains;
20import static com.google.inject.Asserts.assertNotSerializable;
21import static java.lang.annotation.RetentionPolicy.RUNTIME;
22
23
24import junit.framework.TestCase;
25
26import java.io.IOException;
27import java.lang.annotation.Retention;
28import java.util.concurrent.Callable;
29import java.util.concurrent.ExecutionException;
30import java.util.concurrent.ExecutorService;
31import java.util.concurrent.Executors;
32import java.util.concurrent.Future;
33import java.util.concurrent.atomic.AtomicReference;
34
35/**
36 * @author crazybob@google.com (Bob Lee)
37 */
38
39public class InjectorTest extends TestCase {
40
41 @Retention(RUNTIME)
42 @BindingAnnotation @interface Other {}
43
44 @Retention(RUNTIME)
45 @BindingAnnotation @interface S {}
46
47 @Retention(RUNTIME)
48 @BindingAnnotation @interface I {}
49
50 public void testToStringDoesNotInfinitelyRecurse() {
51 Injector injector = Guice.createInjector(Stage.TOOL);
52 injector.toString();
53 injector.getBinding(Injector.class).toString();
54 }
55
56 public void testProviderMethods() throws CreationException {
57 final SampleSingleton singleton = new SampleSingleton();
58 final SampleSingleton other = new SampleSingleton();
59
60 Injector injector = Guice.createInjector(new AbstractModule() {
61 protected void configure() {
62 bind(SampleSingleton.class).toInstance(singleton);
63 bind(SampleSingleton.class)
64 .annotatedWith(Other.class)
65 .toInstance(other);
66 }
67 });
68
69 assertSame(singleton,
70 injector.getInstance(Key.get(SampleSingleton.class)));
71 assertSame(singleton, injector.getInstance(SampleSingleton.class));
72
73 assertSame(other,
74 injector.getInstance(Key.get(SampleSingleton.class, Other.class)));
75 }
76
77 static class SampleSingleton {}
78
79 public void testInjection() throws CreationException {
80 Injector injector = createFooInjector();
81 Foo foo = injector.getInstance(Foo.class);
82
83 assertEquals("test", foo.s);
84 assertEquals("test", foo.bar.getTee().getS());
85 assertSame(foo.bar, foo.copy);
86 assertEquals(5, foo.i);
87 assertEquals(5, foo.bar.getI());
88
89 // Test circular dependency.
90 assertSame(foo.bar, foo.bar.getTee().getBar());
91 }
92
93 private Injector createFooInjector() throws CreationException {
94 return Guice.createInjector(new AbstractModule() {
95 protected void configure() {
96 bind(Bar.class).to(BarImpl.class);
97 bind(Tee.class).to(TeeImpl.class);
98 bindConstant().annotatedWith(S.class).to("test");
99 bindConstant().annotatedWith(I.class).to(5);
100 }
101 });
102 }
103
104 public void testGetInstance() throws CreationException {
105 Injector injector = createFooInjector();
106
107 Bar bar = injector.getInstance(Key.get(Bar.class));
108 assertEquals("test", bar.getTee().getS());
109 assertEquals(5, bar.getI());
110 }
111
112 public void testIntAndIntegerAreInterchangeable()
113 throws CreationException {
114 Injector injector = Guice.createInjector(new AbstractModule() {
115 protected void configure() {
116 bindConstant().annotatedWith(I.class).to(5);
117 }
118 });
119
120 IntegerWrapper iw = injector.getInstance(IntegerWrapper.class);
121 assertEquals(5, (int) iw.i);
122 }
123
124 public void testInjectorApiIsNotSerializable() throws IOException {
125 Injector injector = Guice.createInjector();
126 assertNotSerializable(injector);
127 assertNotSerializable(injector.getProvider(String.class));
128 assertNotSerializable(injector.getBinding(String.class));
129 for (Binding<?> binding : injector.getBindings().values()) {
130 assertNotSerializable(binding);
131 }
132 }
133
134 static class IntegerWrapper {
135 @Inject @I Integer i;
136 }
137
138 static class Foo {
139
140 @Inject Bar bar;
141 @Inject Bar copy;
142
143 @Inject @S String s;
144
145 int i;
146
147 @Inject
148 void setI(@I int i) {
149 this.i = i;
150 }
151 }
152
153 interface Bar {
154
155 Tee getTee();
156 int getI();
157 }
158
159 @Singleton
160 static class BarImpl implements Bar {
161
162 @Inject @I int i;
163
164 Tee tee;
165
166 @Inject
167 void initialize(Tee tee) {
168 this.tee = tee;
169 }
170
171 public Tee getTee() {
172 return tee;
173 }
174
175 public int getI() {
176 return i;
177 }
178 }
179
180 interface Tee {
181
182 String getS();
183 Bar getBar();
184 }
185
186 static class TeeImpl implements Tee {
187
188 final String s;
189 @Inject Bar bar;
190
191 @Inject
192 TeeImpl(@S String s) {
193 this.s = s;
194 }
195
196 public String getS() {
197 return s;
198 }
199
200 public Bar getBar() {
201 return bar;
202 }
203 }
204
205 public void testInjectStatics() throws CreationException {
206 Guice.createInjector(new AbstractModule() {
207 protected void configure() {
208 bindConstant().annotatedWith(S.class).to("test");
209 bindConstant().annotatedWith(I.class).to(5);
210 requestStaticInjection(Static.class);
211 }
212 });
213
214 assertEquals("test", Static.s);
215 assertEquals(5, Static.i);
216 }
217
218 public void testInjectStaticInterface() {
219 try {
220 Guice.createInjector(new AbstractModule() {
221 protected void configure() {
222 requestStaticInjection(Interface.class);
223 }
224 });
225 fail();
226 } catch(CreationException ce) {
227 assertEquals(1, ce.getErrorMessages().size());
228 Asserts.assertContains(
229 ce.getMessage(),
230 "1) " + Interface.class.getName()
231 + " is an interface, but interfaces have no static injection points.",
232 "at " + InjectorTest.class.getName(),
233 "configure");
234 }
235 }
236
237 private static interface Interface {}
238
239 static class Static {
240
241 @Inject @I static int i;
242
243 static String s;
244
245 @Inject static void setS(@S String s) {
246 Static.s = s;
247 }
248 }
249
250 public void testPrivateInjection() throws CreationException {
251 Injector injector = Guice.createInjector(new AbstractModule() {
252 protected void configure() {
253 bind(String.class).toInstance("foo");
254 bind(int.class).toInstance(5);
255 }
256 });
257
258 Private p = injector.getInstance(Private.class);
259 assertEquals("foo", p.fromConstructor);
260 assertEquals(5, p.fromMethod);
261 }
262
263 static class Private {
264 String fromConstructor;
265 int fromMethod;
266
267 @Inject
268 private Private(String fromConstructor) {
269 this.fromConstructor = fromConstructor;
270 }
271
272 @Inject
273 private void setInt(int i) {
274 this.fromMethod = i;
275 }
276 }
277
278 public void testProtectedInjection() throws CreationException {
279 Injector injector = Guice.createInjector(new AbstractModule() {
280 protected void configure() {
281 bind(String.class).toInstance("foo");
282 bind(int.class).toInstance(5);
283 }
284 });
285
286 Protected p = injector.getInstance(Protected.class);
287 assertEquals("foo", p.fromConstructor);
288 assertEquals(5, p.fromMethod);
289 }
290
291 static class Protected {
292 String fromConstructor;
293 int fromMethod;
294
295 @Inject
296 protected Protected(String fromConstructor) {
297 this.fromConstructor = fromConstructor;
298 }
299
300 @Inject
301 protected void setInt(int i) {
302 this.fromMethod = i;
303 }
304 }
305
306 public void testInstanceInjectionHappensAfterFactoriesAreSetUp() {
307 Guice.createInjector(new AbstractModule() {
308 protected void configure() {
309 bind(Object.class).toInstance(new Object() {
310 @Inject Runnable r;
311 });
312
313 bind(Runnable.class).to(MyRunnable.class);
314 }
315 });
316 }
317
318 public void testSubtypeNotProvided() {
319 try {
320 Guice.createInjector().getInstance(Money.class);
321 fail();
322 } catch (ProvisionException expected) {
323 assertContains(expected.getMessage(),
324 Tree.class.getName() + " doesn't provide instances of " + Money.class.getName(),
325 "while locating ", Tree.class.getName(),
326 "while locating ", Money.class.getName());
327 }
328 }
329
330 public void testNotASubtype() {
331 try {
332 Guice.createInjector().getInstance(PineTree.class);
333 fail();
334 } catch (ConfigurationException expected) {
335 assertContains(expected.getMessage(),
336 Tree.class.getName() + " doesn't extend " + PineTree.class.getName(),
337 "while locating ", PineTree.class.getName());
338 }
339 }
340
341 public void testRecursiveImplementationType() {
342 try {
343 Guice.createInjector().getInstance(SeaHorse.class);
344 fail();
345 } catch (ConfigurationException expected) {
346 assertContains(expected.getMessage(),
347 "@ImplementedBy points to the same class it annotates.",
348 "while locating ", SeaHorse.class.getName());
349 }
350 }
351
352 public void testRecursiveProviderType() {
353 try {
354 Guice.createInjector().getInstance(Chicken.class);
355 fail();
356 } catch (ConfigurationException expected) {
357 assertContains(expected.getMessage(),
358 "@ProvidedBy points to the same class it annotates",
359 "while locating ", Chicken.class.getName());
360 }
361 }
362
363 static class MyRunnable implements Runnable {
364 public void run() {}
365 }
366
367 @ProvidedBy(Tree.class)
368 static class Money {}
369
370 static class Tree implements Provider<Object> {
371 public Object get() {
372 return "Money doesn't grow on trees";
373 }
374 }
375
376 @ImplementedBy(Tree.class)
377 static class PineTree extends Tree {}
378
379 @ImplementedBy(SeaHorse.class)
380 static class SeaHorse {}
381
382 @ProvidedBy(Chicken.class)
383 static class Chicken implements Provider<Chicken> {
384 public Chicken get() {
385 return this;
386 }
387 }
388
389 public void testJitBindingFromAnotherThreadDuringInjection() {
390 final ExecutorService executorService = Executors.newSingleThreadExecutor();
391 final AtomicReference<JustInTime> got = new AtomicReference<JustInTime>();
392
393 Guice.createInjector(new AbstractModule() {
394 protected void configure() {
395 requestInjection(new Object() {
396 @Inject void initialize(final Injector injector)
397 throws ExecutionException, InterruptedException {
398 Future<JustInTime> future = executorService.submit(new Callable<JustInTime>() {
399 public JustInTime call() throws Exception {
400 return injector.getInstance(JustInTime.class);
401 }
402 });
403 got.set(future.get());
404 }
405 });
406 }
407 });
408
409 assertNotNull(got.get());
410 }
411
412 static class JustInTime {}
413}