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 
17 package com.google.inject;
18 
19 import static com.google.inject.name.Names.named;
20 
21 import com.google.inject.name.Named;
22 
23 import junit.framework.TestCase;
24 
25 import java.util.Arrays;
26 import java.util.List;
27 
28 /**
29  * @author crazybob@google.com (Bob Lee)
30  */
31 public class ProviderInjectionTest extends TestCase {
32 
testProviderInjection()33   public void testProviderInjection() throws CreationException {
34     Injector injector = Guice.createInjector(new AbstractModule() {
35       protected void configure() {
36         bind(Bar.class);
37         bind(SampleSingleton.class).in(Scopes.SINGLETON);
38       }
39     });
40 
41     Foo foo = injector.getInstance(Foo.class);
42 
43     Bar bar = foo.barProvider.get();
44     assertNotNull(bar);
45     assertNotSame(bar, foo.barProvider.get());
46 
47     SampleSingleton singleton = foo.singletonProvider.get();
48     assertNotNull(singleton);
49     assertSame(singleton, foo.singletonProvider.get());
50   }
51 
52   /** Test for bug 155. */
testProvidersAreInjectedWhenBound()53   public void testProvidersAreInjectedWhenBound() {
54     Module m = new AbstractModule() {
55       @Override
56       protected void configure() {
57         bind(Bar.class).toProvider(new Provider<Bar>() {
58           @SuppressWarnings("unused")
59           @Inject void cantBeCalled(Baz baz) {
60             fail("Can't have called this method since Baz is not bound.");
61           }
62           public Bar get() {
63             return new Bar() {};
64           }
65         });
66       }
67     };
68 
69     try {
70       Guice.createInjector(m);
71       fail("Should have thrown a CreationException");
72     }
73     catch (CreationException expected) {
74     }
75   }
76 
77   /**
78    * When custom providers are used at injector creation time, they should be
79    * injected before use. In this testcase, we verify that a provider for
80    * List.class is injected before it is used.
81    */
testProvidersAreInjectedBeforeTheyAreUsed()82   public void testProvidersAreInjectedBeforeTheyAreUsed() {
83     Injector injector = Guice.createInjector(new AbstractModule() {
84       public void configure() {
85         // should bind String to "[true]"
86         bind(String.class).toProvider(new Provider<String>() {
87           private String value;
88           @Inject void initialize(List list) {
89             value = list.toString();
90           }
91           public String get() {
92             return value;
93           }
94         });
95 
96         // should bind List to [true]
97         bind(List.class).toProvider(new Provider<List>() {
98           @Inject Boolean injectedYet = Boolean.FALSE;
99           public List get() {
100             return Arrays.asList(injectedYet);
101           }
102         });
103 
104         // should bind Boolean to true
105         bind(Boolean.class).toInstance(Boolean.TRUE);
106       }
107     });
108 
109     assertEquals("Providers not injected before use",
110         "[true]",
111         injector.getInstance(String.class));
112   }
113 
114   /**
115    * This test ensures that regardless of binding order, instances are injected
116    * before they are used. It injects mutable Count objects and records their
117    * value at the time that they're injected.
118    */
testCreationTimeInjectionOrdering()119   public void testCreationTimeInjectionOrdering() {
120     Injector injector = Guice.createInjector(new AbstractModule() {
121       protected void configure() {
122         // instance injection
123         bind(Count.class).annotatedWith(named("a")).toInstance(new Count(0) {
124           @Inject void initialize(@Named("b") Count bCount) {
125             value = bCount.value + 1;
126           }
127         });
128 
129         // provider injection
130         bind(Count.class).annotatedWith(named("b")).toProvider(new Provider<Count>() {
131           Count count;
132           @Inject void initialize(@Named("c") Count cCount) {
133             count = new Count(cCount.value + 2);
134           }
135           public Count get() {
136             return count;
137           }
138         });
139 
140         // field and method injection, fields first
141         bind(Count.class).annotatedWith(named("c")).toInstance(new Count(0) {
142           @Inject @Named("d") Count dCount;
143           @Inject void initialize(@Named("e") Count eCount) {
144             value = dCount.value + eCount.value + 4;
145           }
146         });
147 
148         // static injection
149         requestStaticInjection(StaticallyInjectable.class);
150 
151         bind(Count.class).annotatedWith(named("d")).toInstance(new Count(8));
152         bind(Count.class).annotatedWith(named("e")).toInstance(new Count(16));
153       }
154     });
155 
156     assertEquals(28, injector.getInstance(Key.get(Count.class, named("c"))).value);
157     assertEquals(30, injector.getInstance(Key.get(Count.class, named("b"))).value);
158     assertEquals(31, injector.getInstance(Key.get(Count.class, named("a"))).value);
159     assertEquals(28, StaticallyInjectable.cCountAtInjectionTime);
160   }
161 
162   static class Count {
163     int value;
Count(int value)164     Count(int value) {
165       this.value = value;
166     }
167   }
168 
169   static class StaticallyInjectable {
170     static int cCountAtInjectionTime;
initialize(@amed"c") Count cCount)171     @Inject static void initialize(@Named("c") Count cCount) {
172       cCountAtInjectionTime = cCount.value;
173     }
174   }
175 
176   static class Foo {
177     @Inject Provider<Bar> barProvider;
178     @Inject Provider<SampleSingleton> singletonProvider;
179   }
180 
181   static class Bar {}
182 
183   static class SampleSingleton {}
184 
185   interface Baz { }
186 
187 }
188