• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 
17 package com.googlecode.guice;
18 
19 import static com.google.inject.Asserts.assertContains;
20 import static java.lang.annotation.RetentionPolicy.RUNTIME;
21 
22 import com.google.inject.AbstractModule;
23 import com.google.inject.Binding;
24 import com.google.inject.CreationException;
25 import com.google.inject.Guice;
26 import com.google.inject.Injector;
27 import com.google.inject.Key;
28 import com.google.inject.Scope;
29 import com.google.inject.Scopes;
30 import com.google.inject.Stage;
31 import com.google.inject.TypeLiteral;
32 import com.google.inject.name.Names;
33 import com.google.inject.spi.Dependency;
34 import com.google.inject.spi.HasDependencies;
35 import com.google.inject.util.Providers;
36 import java.lang.annotation.Annotation;
37 import java.lang.annotation.Retention;
38 import java.util.Set;
39 import javax.inject.Inject;
40 import javax.inject.Named;
41 import javax.inject.Provider;
42 import javax.inject.Qualifier;
43 import javax.inject.Singleton;
44 import junit.framework.TestCase;
45 
46 public class Jsr330Test extends TestCase {
47 
48   private final B b = new B();
49   private final C c = new C();
50   private final D d = new D();
51   private final E e = new E();
52 
53   @Override
setUp()54   protected void setUp() throws Exception {
55     J.nextInstanceId = 0;
56     K.nextInstanceId = 0;
57   }
58 
testInject()59   public void testInject() {
60     Injector injector =
61         Guice.createInjector(
62             new AbstractModule() {
63               @Override
64               protected void configure() {
65                 bind(B.class).toInstance(b);
66                 bind(C.class).toInstance(c);
67                 bind(D.class).toInstance(d);
68                 bind(E.class).toInstance(e);
69                 bind(A.class);
70               }
71             });
72 
73     A a = injector.getInstance(A.class);
74     assertSame(b, a.b);
75     assertSame(c, a.c);
76     assertSame(d, a.d);
77     assertSame(e, a.e);
78   }
79 
testQualifiedInject()80   public void testQualifiedInject() {
81     Injector injector =
82         Guice.createInjector(
83             new AbstractModule() {
84               @Override
85               protected void configure() {
86                 bind(B.class).annotatedWith(Names.named("jodie")).toInstance(b);
87                 bind(C.class).annotatedWith(Red.class).toInstance(c);
88                 bind(D.class).annotatedWith(RED).toInstance(d);
89                 bind(E.class).annotatedWith(Names.named("jesse")).toInstance(e);
90                 bind(F.class);
91               }
92             });
93 
94     F f = injector.getInstance(F.class);
95     assertSame(b, f.b);
96     assertSame(c, f.c);
97     assertSame(d, f.d);
98     assertSame(e, f.e);
99   }
100 
testProviderInject()101   public void testProviderInject() {
102     Injector injector =
103         Guice.createInjector(
104             new AbstractModule() {
105               @Override
106               protected void configure() {
107                 bind(B.class).annotatedWith(Names.named("jodie")).toInstance(b);
108                 bind(C.class).toInstance(c);
109                 bind(D.class).annotatedWith(RED).toInstance(d);
110                 bind(E.class).toInstance(e);
111                 bind(G.class);
112               }
113             });
114 
115     G g = injector.getInstance(G.class);
116     assertSame(b, g.bProvider.get());
117     assertSame(c, g.cProvider.get());
118     assertSame(d, g.dProvider.get());
119     assertSame(e, g.eProvider.get());
120   }
121 
testScopeAnnotation()122   public void testScopeAnnotation() {
123     final TestScope scope = new TestScope();
124 
125     Injector injector =
126         Guice.createInjector(
127             new AbstractModule() {
128               @Override
129               protected void configure() {
130                 bind(B.class).in(scope);
131                 bind(C.class).in(TestScoped.class);
132                 bindScope(TestScoped.class, scope);
133               }
134             });
135 
136     B b = injector.getInstance(B.class);
137     assertSame(b, injector.getInstance(B.class));
138     assertSame(b, injector.getInstance(B.class));
139 
140     C c = injector.getInstance(C.class);
141     assertSame(c, injector.getInstance(C.class));
142     assertSame(c, injector.getInstance(C.class));
143 
144     H h = injector.getInstance(H.class);
145     assertSame(h, injector.getInstance(H.class));
146     assertSame(h, injector.getInstance(H.class));
147 
148     scope.reset();
149 
150     assertNotSame(b, injector.getInstance(B.class));
151     assertNotSame(c, injector.getInstance(C.class));
152     assertNotSame(h, injector.getInstance(H.class));
153   }
154 
testSingleton()155   public void testSingleton() {
156     Injector injector =
157         Guice.createInjector(
158             new AbstractModule() {
159               @Override
160               protected void configure() {
161                 bind(B.class).in(Singleton.class);
162               }
163             });
164 
165     B b = injector.getInstance(B.class);
166     assertSame(b, injector.getInstance(B.class));
167     assertSame(b, injector.getInstance(B.class));
168 
169     J j = injector.getInstance(J.class);
170     assertSame(j, injector.getInstance(J.class));
171     assertSame(j, injector.getInstance(J.class));
172   }
173 
testEagerSingleton()174   public void testEagerSingleton() {
175     Guice.createInjector(
176         Stage.PRODUCTION,
177         new AbstractModule() {
178           @Override
179           protected void configure() {
180             bind(J.class);
181             bind(K.class).in(Singleton.class);
182           }
183         });
184 
185     assertEquals(1, J.nextInstanceId);
186     assertEquals(1, K.nextInstanceId);
187   }
188 
testScopesIsSingleton()189   public void testScopesIsSingleton() {
190     Injector injector =
191         Guice.createInjector(
192             new AbstractModule() {
193               @Override
194               protected void configure() {
195                 bind(J.class);
196                 bind(K.class).in(Singleton.class);
197               }
198             });
199 
200     assertTrue(Scopes.isSingleton(injector.getBinding(J.class)));
201     assertTrue(Scopes.isSingleton(injector.getBinding(K.class)));
202   }
203 
testInjectingFinalFieldsIsForbidden()204   public void testInjectingFinalFieldsIsForbidden() {
205     try {
206       Guice.createInjector(
207           new AbstractModule() {
208             @Override
209             protected void configure() {
210               bind(L.class);
211             }
212           });
213       fail();
214     } catch (CreationException expected) {
215       assertContains(
216           expected.getMessage(), "1) Injected field " + L.class.getName() + ".b cannot be final.");
217     }
218   }
219 
testInjectingAbstractMethodsIsForbidden()220   public void testInjectingAbstractMethodsIsForbidden() {
221     try {
222       Guice.createInjector(
223           new AbstractModule() {
224             @Override
225             protected void configure() {
226               bind(M.class);
227             }
228           });
229       fail();
230     } catch (CreationException expected) {
231       assertContains(
232           expected.getMessage(),
233           "1) Injected method " + AbstractM.class.getName() + ".setB() cannot be abstract.");
234     }
235   }
236 
testInjectingMethodsWithTypeParametersIsForbidden()237   public void testInjectingMethodsWithTypeParametersIsForbidden() {
238     try {
239       Guice.createInjector(
240           new AbstractModule() {
241             @Override
242             protected void configure() {
243               bind(N.class);
244             }
245           });
246       fail();
247     } catch (CreationException expected) {
248       assertContains(
249           expected.getMessage(),
250           "1) Injected method "
251               + N.class.getName()
252               + ".setB() cannot declare type parameters of its own.");
253     }
254   }
255 
testInjectingMethodsWithNonVoidReturnTypes()256   public void testInjectingMethodsWithNonVoidReturnTypes() {
257     Guice.createInjector(
258         new AbstractModule() {
259           @Override
260           protected void configure() {
261             bind(P.class);
262           }
263         });
264   }
265 
266   /**
267    * This test verifies that we can compile bindings to provider instances whose compile-time type
268    * implements javax.inject.Provider but not com.google.inject.Provider. For binary compatibility,
269    * we don't (and won't) support binding to instances of javax.inject.Provider.
270    */
testBindProviderClass()271   public void testBindProviderClass() {
272     Injector injector =
273         Guice.createInjector(
274             new AbstractModule() {
275               @Override
276               protected void configure() {
277                 bind(B.class).toProvider(BProvider.class);
278                 bind(B.class).annotatedWith(Names.named("1")).toProvider(BProvider.class);
279                 bind(B.class).annotatedWith(Names.named("2")).toProvider(Key.get(BProvider.class));
280                 bind(B.class)
281                     .annotatedWith(Names.named("3"))
282                     .toProvider(TypeLiteral.get(BProvider.class));
283               }
284             });
285 
286     injector.getInstance(Key.get(B.class));
287     injector.getInstance(Key.get(B.class, Names.named("1")));
288     injector.getInstance(Key.get(B.class, Names.named("2")));
289     injector.getInstance(Key.get(B.class, Names.named("3")));
290   }
291 
testGuicify330Provider()292   public void testGuicify330Provider() {
293     Provider<String> jsr330Provider =
294         new Provider<String>() {
295           @Override
296           public String get() {
297             return "A";
298           }
299 
300           @Override
301           public String toString() {
302             return "jsr330Provider";
303           }
304         };
305 
306     com.google.inject.Provider<String> guicified = Providers.guicify(jsr330Provider);
307     assertEquals("guicified(jsr330Provider)", guicified.toString());
308     assertEquals("A", guicified.get());
309 
310     // when you guicify the Guice-friendly, it's a no-op
311     assertSame(guicified, Providers.guicify(guicified));
312 
313     assertFalse(guicified instanceof HasDependencies);
314   }
315 
testGuicifyWithDependencies()316   public void testGuicifyWithDependencies() {
317     Provider<String> jsr330Provider =
318         new Provider<String>() {
319           @Inject double d;
320           int i;
321 
322           @Inject
323           void injectMe(int i) {
324             this.i = i;
325           }
326 
327           @Override
328           public String get() {
329             return d + "-" + i;
330           }
331         };
332 
333     final com.google.inject.Provider<String> guicified = Providers.guicify(jsr330Provider);
334     assertTrue(guicified instanceof HasDependencies);
335     Set<Dependency<?>> actual = ((HasDependencies) guicified).getDependencies();
336     validateDependencies(actual, jsr330Provider.getClass());
337 
338     Injector injector =
339         Guice.createInjector(
340             new AbstractModule() {
341               @Override
342               protected void configure() {
343                 bind(String.class).toProvider(guicified);
344                 bind(int.class).toInstance(1);
345                 bind(double.class).toInstance(2.0d);
346               }
347             });
348 
349     Binding<String> binding = injector.getBinding(String.class);
350     assertEquals("2.0-1", binding.getProvider().get());
351     validateDependencies(actual, jsr330Provider.getClass());
352   }
353 
validateDependencies(Set<Dependency<?>> actual, Class<?> owner)354   private void validateDependencies(Set<Dependency<?>> actual, Class<?> owner) {
355     assertEquals(actual.toString(), 2, actual.size());
356     Dependency<?> dDep = null;
357     Dependency<?> iDep = null;
358     for (Dependency<?> dep : actual) {
359       if (dep.getKey().equals(Key.get(Double.class))) {
360         dDep = dep;
361       } else if (dep.getKey().equals(Key.get(Integer.class))) {
362         iDep = dep;
363       }
364     }
365     assertNotNull(dDep);
366     assertNotNull(iDep);
367     assertEquals(TypeLiteral.get(owner), dDep.getInjectionPoint().getDeclaringType());
368     assertEquals("d", dDep.getInjectionPoint().getMember().getName());
369     assertEquals(-1, dDep.getParameterIndex());
370 
371     assertEquals(TypeLiteral.get(owner), iDep.getInjectionPoint().getDeclaringType());
372     assertEquals("injectMe", iDep.getInjectionPoint().getMember().getName());
373     assertEquals(0, iDep.getParameterIndex());
374   }
375 
376   static class A {
377     final B b;
378     @Inject C c;
379     D d;
380     E e;
381 
382     @Inject
A(B b)383     A(B b) {
384       this.b = b;
385     }
386 
387     @Inject
injectD(D d, E e)388     void injectD(D d, E e) {
389       this.d = d;
390       this.e = e;
391     }
392   }
393 
394   static class B {}
395 
396   static class C {}
397 
398   static class D {}
399 
400   static class E {}
401 
402   static class F {
403     final B b;
404     @Inject @Red C c;
405     D d;
406     E e;
407 
408     @Inject
F(@amed"jodie") B b)409     F(@Named("jodie") B b) {
410       this.b = b;
411     }
412 
413     @Inject
injectD(@ed D d, @Named("jesse") E e)414     void injectD(@Red D d, @Named("jesse") E e) {
415       this.d = d;
416       this.e = e;
417     }
418   }
419 
420   @Qualifier
421   @Retention(RUNTIME)
422   @interface Red {}
423 
424   public static final Red RED =
425       new Red() {
426         @Override
427         public Class<? extends Annotation> annotationType() {
428           return Red.class;
429         }
430 
431         @Override
432         public boolean equals(Object obj) {
433           return obj instanceof Red;
434         }
435 
436         @Override
437         public int hashCode() {
438           return 0;
439         }
440       };
441 
442   static class G {
443     final Provider<B> bProvider;
444     @Inject Provider<C> cProvider;
445     Provider<D> dProvider;
446     Provider<E> eProvider;
447 
448     @Inject
G(@amed"jodie") Provider<B> bProvider)449     G(@Named("jodie") Provider<B> bProvider) {
450       this.bProvider = bProvider;
451     }
452 
453     @Inject
injectD(@ed Provider<D> dProvider, Provider<E> eProvider)454     void injectD(@Red Provider<D> dProvider, Provider<E> eProvider) {
455       this.dProvider = dProvider;
456       this.eProvider = eProvider;
457     }
458   }
459 
460   @javax.inject.Scope
461   @Retention(RUNTIME)
462   @interface TestScoped {}
463 
464   static class TestScope implements Scope {
465     private int now = 0;
466 
467     @Override
scope( Key<T> key, final com.google.inject.Provider<T> unscoped)468     public <T> com.google.inject.Provider<T> scope(
469         Key<T> key, final com.google.inject.Provider<T> unscoped) {
470       return new com.google.inject.Provider<T>() {
471         private T value;
472         private int snapshotTime = -1;
473 
474         @Override
475         public T get() {
476           if (snapshotTime != now) {
477             value = unscoped.get();
478             snapshotTime = now;
479           }
480           return value;
481         }
482       };
483     }
484 
reset()485     public void reset() {
486       now++;
487     }
488   }
489 
490   @TestScoped
491   static class H {}
492 
493   @Singleton
494   static class J {
495     static int nextInstanceId = 0;
496     int instanceId = nextInstanceId++;
497   }
498 
499   static class K {
500     static int nextInstanceId = 0;
501     int instanceId = nextInstanceId++;
502   }
503 
504   static class L {
505     @SuppressWarnings("InjectJavaxInjectOnFinalField")
506     @Inject
507     final B b = null;
508   }
509 
510   abstract static class AbstractM {
511     @SuppressWarnings("JavaxInjectOnAbstractMethod")
512     @Inject
setB(B b)513     abstract void setB(B b);
514   }
515 
516   static class M extends AbstractM {
517     @Override
518     @SuppressWarnings("OverridesJavaxInjectableMethod")
setB(B b)519     void setB(B b) {}
520   }
521 
522   static class N {
523     @Inject
setB(B b)524     <T> void setB(B b) {}
525   }
526 
527   static class P {
528     @Inject
setB(B b)529     B setB(B b) {
530       return b;
531     }
532   }
533 
534   static class BProvider implements Provider<B> {
535     @Override
get()536     public B get() {
537       return new B();
538     }
539   }
540 }
541