xref: /aosp_15_r20/external/guice/core/test/com/google/inject/ParentInjectorTest.java (revision dc5640d1ceac12a29404866b9a53df952a7a6c47)
1 /*
2 Copyright (C) 2007 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.Asserts.assertContains;
20 import static com.google.inject.Asserts.getDeclaringSourcePart;
21 import static java.lang.annotation.ElementType.TYPE;
22 import static java.lang.annotation.RetentionPolicy.RUNTIME;
23 
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.Iterables;
26 import com.google.inject.matcher.Matchers;
27 import com.google.inject.name.Names;
28 import com.google.inject.spi.TypeConverter;
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.Target;
31 import java.util.List;
32 import junit.framework.TestCase;
33 
34 /** @author [email protected] (Jesse Wilson) */
35 public class ParentInjectorTest extends TestCase {
36 
testParentAndChildCannotShareExplicitBindings()37   public void testParentAndChildCannotShareExplicitBindings() {
38     Injector parent = Guice.createInjector(bindsA);
39     try {
40       parent.createChildInjector(bindsA);
41       fail("Created the same explicit binding on both parent and child");
42     } catch (CreationException e) {
43       assertContains(
44           e.getMessage(),
45           "A binding to ",
46           A.class.getName(),
47           " was already configured",
48           " at ",
49           getClass().getName(),
50           getDeclaringSourcePart(getClass()),
51           " at ",
52           getClass().getName(),
53           getDeclaringSourcePart(getClass()));
54     }
55   }
56 
testParentJitBindingWontClobberChildBinding()57   public void testParentJitBindingWontClobberChildBinding() {
58     Injector parent = Guice.createInjector();
59     parent.createChildInjector(bindsA);
60     try {
61       parent.getInstance(A.class);
62       fail("Created a just-in-time binding on the parent that's the same as a child's binding");
63     } catch (ConfigurationException e) {
64       assertContains(
65           e.getMessage(),
66           "Unable to create binding for " + A.class.getName(),
67           "It was already configured on one or more child injectors or private modules",
68           "bound at " + bindsA.getClass().getName() + ".configure(",
69           "If it was in a PrivateModule, did you forget to expose the binding?",
70           "while locating " + A.class.getName());
71     }
72   }
73 
testChildCannotBindToAParentJitBinding()74   public void testChildCannotBindToAParentJitBinding() {
75     Injector parent = Guice.createInjector();
76     parent.getInstance(A.class);
77     try {
78       parent.createChildInjector(bindsA);
79       fail();
80     } catch (CreationException ce) {
81       assertContains(
82           Iterables.getOnlyElement(ce.getErrorMessages()).getMessage(),
83           "A just-in-time binding to "
84               + A.class.getName()
85               + " was already configured on a parent injector.");
86     }
87   }
88 
testJustInTimeBindingsAreSharedWithParentIfPossible()89   public void testJustInTimeBindingsAreSharedWithParentIfPossible() {
90     Injector parent = Guice.createInjector();
91     Injector child = parent.createChildInjector();
92     assertSame(child.getInstance(A.class), parent.getInstance(A.class));
93 
94     Injector anotherChild = parent.createChildInjector();
95     assertSame(anotherChild.getInstance(A.class), parent.getInstance(A.class));
96 
97     Injector grandchild = child.createChildInjector();
98     assertSame(grandchild.getInstance(A.class), parent.getInstance(A.class));
99   }
100 
testBindingsInherited()101   public void testBindingsInherited() {
102     Injector parent = Guice.createInjector(bindsB);
103     Injector child = parent.createChildInjector();
104     assertSame(RealB.class, child.getInstance(B.class).getClass());
105   }
106 
testGetParent()107   public void testGetParent() {
108     Injector top = Guice.createInjector(bindsA);
109     Injector middle = top.createChildInjector(bindsB);
110     Injector bottom = middle.createChildInjector();
111     assertSame(middle, bottom.getParent());
112     assertSame(top, middle.getParent());
113     assertNull(top.getParent());
114   }
115 
testChildBindingsNotVisibleToParent()116   public void testChildBindingsNotVisibleToParent() {
117     Injector parent = Guice.createInjector();
118     parent.createChildInjector(bindsB);
119     try {
120       parent.getBinding(B.class);
121       fail();
122     } catch (ConfigurationException expected) {
123     }
124   }
125 
testScopesInherited()126   public void testScopesInherited() {
127     Injector parent =
128         Guice.createInjector(
129             new AbstractModule() {
130               @Override
131               protected void configure() {
132                 bindScope(MyScope.class, Scopes.SINGLETON);
133               }
134             });
135     Injector child =
136         parent.createChildInjector(
137             new AbstractModule() {
138               @Override
139               protected void configure() {
140                 bind(A.class).in(MyScope.class);
141               }
142             });
143     assertSame(child.getInstance(A.class), child.getInstance(A.class));
144   }
145 
146   /*if[AOP]*/
147   private final org.aopalliance.intercept.MethodInterceptor returnNullInterceptor =
148       new org.aopalliance.intercept.MethodInterceptor() {
149         @Override
150         public Object invoke(org.aopalliance.intercept.MethodInvocation methodInvocation) {
151           return null;
152         }
153       };
154 
testInterceptorsInherited()155   public void testInterceptorsInherited() {
156     Injector parent =
157         Guice.createInjector(
158             new AbstractModule() {
159               @Override
160               protected void configure() {
161                 super.bindInterceptor(
162                     Matchers.any(),
163                     Matchers.returns(Matchers.identicalTo(A.class)),
164                     returnNullInterceptor);
165               }
166             });
167 
168     Injector child =
169         parent.createChildInjector(
170             new AbstractModule() {
171               @Override
172               protected void configure() {
173                 bind(C.class);
174               }
175             });
176 
177     assertNull(child.getInstance(C.class).interceptedMethod());
178   }
179   /*end[AOP]*/
180 
testTypeConvertersInherited()181   public void testTypeConvertersInherited() {
182     Injector parent = Guice.createInjector(bindListConverterModule);
183     Injector child = parent.createChildInjector(bindStringNamedB);
184 
185     assertEquals(ImmutableList.of(), child.getInstance(Key.get(List.class, Names.named("B"))));
186   }
187 
testTypeConvertersConflicting()188   public void testTypeConvertersConflicting() {
189     Injector parent = Guice.createInjector(bindListConverterModule);
190     Injector child = parent.createChildInjector(bindListConverterModule, bindStringNamedB);
191 
192     try {
193       child.getInstance(Key.get(List.class, Names.named("B")));
194       fail();
195     } catch (ConfigurationException expected) {
196       Asserts.assertContains(expected.getMessage(), "Multiple converters can convert");
197     }
198   }
199 
testInjectorInjectionSpanningInjectors()200   public void testInjectorInjectionSpanningInjectors() {
201     Injector parent = Guice.createInjector();
202     Injector child =
203         parent.createChildInjector(
204             new AbstractModule() {
205               @Override
206               protected void configure() {
207                 bind(D.class);
208               }
209             });
210 
211     D d = child.getInstance(D.class);
212     assertSame(d.injector, child);
213 
214     E e = child.getInstance(E.class);
215     assertSame(e.injector, parent);
216   }
217 
testSeveralLayersOfHierarchy()218   public void testSeveralLayersOfHierarchy() {
219     Injector top = Guice.createInjector(bindsA);
220     Injector left = top.createChildInjector();
221     Injector leftLeft = left.createChildInjector(bindsD);
222     Injector right = top.createChildInjector(bindsD);
223 
224     assertSame(leftLeft, leftLeft.getInstance(D.class).injector);
225     assertSame(right, right.getInstance(D.class).injector);
226     assertSame(top, leftLeft.getInstance(E.class).injector);
227     assertSame(top.getInstance(A.class), leftLeft.getInstance(A.class));
228 
229     Injector leftRight = left.createChildInjector(bindsD);
230     assertSame(leftRight, leftRight.getInstance(D.class).injector);
231 
232     try {
233       top.getInstance(D.class);
234       fail();
235     } catch (ConfigurationException expected) {
236     }
237 
238     try {
239       left.getInstance(D.class);
240       fail();
241     } catch (ConfigurationException expected) {
242     }
243   }
244 
testScopeBoundInChildInjectorOnly()245   public void testScopeBoundInChildInjectorOnly() {
246     Injector parent = Guice.createInjector();
247     Injector child =
248         parent.createChildInjector(
249             new AbstractModule() {
250               @Override
251               protected void configure() {
252                 bindScope(MyScope.class, Scopes.SINGLETON);
253               }
254             });
255 
256     try {
257       parent.getProvider(F.class);
258       fail();
259     } catch (ConfigurationException expected) {
260       assertContains(
261           expected.getMessage(),
262           "No scope is bound to com.google.inject.ParentInjectorTest$MyScope.",
263           "at " + F.class.getName() + ".class(ParentInjectorTest.java",
264           "  while locating " + F.class.getName());
265     }
266 
267     assertNotNull(child.getProvider(F.class).get());
268   }
269 
testErrorInParentButOkayInChild()270   public void testErrorInParentButOkayInChild() {
271     Injector parent = Guice.createInjector();
272     Injector childInjector =
273         parent.createChildInjector(
274             new AbstractModule() {
275               @Override
276               protected void configure() {
277                 bindScope(MyScope.class, Scopes.SINGLETON);
278                 bind(Object.class).to(F.class);
279               }
280             });
281     Object one = childInjector.getInstance(Object.class);
282     Object two = childInjector.getInstance(Object.class);
283     assertSame(one, two);
284   }
285 
testErrorInParentAndChild()286   public void testErrorInParentAndChild() {
287     Injector parent = Guice.createInjector();
288     Injector childInjector = parent.createChildInjector();
289 
290     try {
291       childInjector.getInstance(G.class);
292       fail();
293     } catch (ConfigurationException expected) {
294       assertContains(
295           expected.getMessage(),
296           "No scope is bound to " + MyScope.class.getName(),
297           "at " + F.class.getName() + ".class(ParentInjectorTest.java:",
298           "  while locating " + G.class.getName());
299     }
300   }
301 
302   @Singleton
303   static class A {}
304 
305   private final Module bindsA =
306       new AbstractModule() {
307         @Override
308         protected void configure() {
309           bind(A.class).toInstance(new A());
310         }
311       };
312 
313   interface B {}
314 
315   static class RealB implements B {}
316 
317   private final Module bindsB =
318       new AbstractModule() {
319         @Override
320         protected void configure() {
321           bind(B.class).to(RealB.class);
322         }
323       };
324 
325   @Target(TYPE)
326   @Retention(RUNTIME)
327   @ScopeAnnotation
328   public @interface MyScope {}
329 
330   private final TypeConverter listConverter =
331       new TypeConverter() {
332         @Override
333         public Object convert(String value, TypeLiteral<?> toType) {
334           return ImmutableList.of();
335         }
336       };
337 
338   private final Module bindListConverterModule =
339       new AbstractModule() {
340         @Override
341         protected void configure() {
342           convertToTypes(Matchers.any(), listConverter);
343         }
344       };
345 
346   private final Module bindStringNamedB =
347       new AbstractModule() {
348         @Override
349         protected void configure() {
350           bind(String.class).annotatedWith(Names.named("B")).toInstance("buzz");
351         }
352       };
353 
354   public static class C {
interceptedMethod()355     public A interceptedMethod() {
356       return new A();
357     }
358   }
359 
360   static class D {
361     @Inject Injector injector;
362   }
363 
364   static class E {
365     @Inject Injector injector;
366   }
367 
368   private final Module bindsD =
369       new AbstractModule() {
370         @Override
371         protected void configure() {
372           bind(D.class);
373         }
374       };
375 
376   @MyScope
377   static class F implements G {}
378 
379   @ImplementedBy(F.class)
380   interface G {}
381 }
382