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.google.inject;
18 
19 import static com.google.inject.Asserts.assertContains;
20 
21 import com.google.inject.name.Names;
22 import com.google.inject.util.Providers;
23 
24 import junit.framework.AssertionFailedError;
25 import junit.framework.TestCase;
26 
27 import java.util.concurrent.atomic.AtomicReference;
28 
29 /**
30  * @author jessewilson@google.com (Jesse Wilson)
31  */
32 public class MembersInjectorTest extends TestCase {
33 
34   private static final A<C> uninjectableA = new A<C>() {
35     @Override void doNothing() {
36       throw new AssertionFailedError();
37     }
38   };
39 
40   private static final B uninjectableB = new B() {
41     @Override void doNothing() {
42       throw new AssertionFailedError();
43     }
44   };
45 
46   private static final C myFavouriteC = new C();
47 
testMembersInjectorFromBinder()48   public void testMembersInjectorFromBinder() {
49     final AtomicReference<MembersInjector<A<C>>> aMembersInjectorReference
50         = new AtomicReference<MembersInjector<A<C>>>();
51     final AtomicReference<MembersInjector<B>> bMembersInjectorReference
52         = new AtomicReference<MembersInjector<B>>();
53 
54     Guice.createInjector(new AbstractModule() {
55       @Override protected void configure() {
56         MembersInjector<A<C>> aMembersInjector = getMembersInjector(new TypeLiteral<A<C>>() {});
57         try {
58           aMembersInjector.injectMembers(uninjectableA);
59           fail();
60         } catch (IllegalStateException expected) {
61           assertContains(expected.getMessage(),
62               "This MembersInjector cannot be used until the Injector has been created.");
63         }
64 
65         MembersInjector<B> bMembersInjector = getMembersInjector(B.class);
66         try {
67           bMembersInjector.injectMembers(uninjectableB);
68           fail();
69         } catch (IllegalStateException expected) {
70           assertContains(expected.getMessage(),
71               "This MembersInjector cannot be used until the Injector has been created.");
72         }
73 
74         aMembersInjectorReference.set(aMembersInjector);
75         bMembersInjectorReference.set(bMembersInjector);
76 
77         assertEquals("MembersInjector<java.lang.String>",
78             getMembersInjector(String.class).toString());
79 
80         bind(C.class).toInstance(myFavouriteC);
81       }
82     });
83 
84     A<C> injectableA = new A<C>();
85     aMembersInjectorReference.get().injectMembers(injectableA);
86     assertSame(myFavouriteC, injectableA.t);
87     assertSame(myFavouriteC, injectableA.b.c);
88 
89     B injectableB = new B();
90     bMembersInjectorReference.get().injectMembers(injectableB);
91     assertSame(myFavouriteC, injectableB.c);
92 
93     B anotherInjectableB = new B();
94     bMembersInjectorReference.get().injectMembers(anotherInjectableB);
95     assertSame(myFavouriteC, anotherInjectableB.c);
96   }
97 
testMembersInjectorFromInjector()98   public void testMembersInjectorFromInjector() {
99     Injector injector = Guice.createInjector(new AbstractModule() {
100       protected void configure() {
101         bind(C.class).toInstance(myFavouriteC);
102       }
103     });
104 
105     MembersInjector<A<C>> aMembersInjector
106         = injector.getMembersInjector(new TypeLiteral<A<C>>() {});
107     MembersInjector<B> bMembersInjector = injector.getMembersInjector(B.class);
108 
109     A<C> injectableA = new A<C>();
110     aMembersInjector.injectMembers(injectableA);
111     assertSame(myFavouriteC, injectableA.t);
112     assertSame(myFavouriteC, injectableA.b.c);
113 
114     B injectableB = new B();
115     bMembersInjector.injectMembers(injectableB);
116     assertSame(myFavouriteC, injectableB.c);
117 
118     B anotherInjectableB = new B();
119     bMembersInjector.injectMembers(anotherInjectableB);
120     assertSame(myFavouriteC, anotherInjectableB.c);
121 
122     assertEquals("MembersInjector<java.lang.String>",
123         injector.getMembersInjector(String.class).toString());
124   }
125 
testMembersInjectorWithNonInjectedTypes()126   public void testMembersInjectorWithNonInjectedTypes() {
127     Injector injector = Guice.createInjector();
128 
129     MembersInjector<NoInjectedMembers> membersInjector
130         = injector.getMembersInjector(NoInjectedMembers.class);
131 
132     membersInjector.injectMembers(new NoInjectedMembers());
133     membersInjector.injectMembers(new NoInjectedMembers());
134   }
135 
testInjectionFailure()136   public void testInjectionFailure() {
137     Injector injector = Guice.createInjector();
138 
139     MembersInjector<InjectionFailure> membersInjector
140         = injector.getMembersInjector(InjectionFailure.class);
141 
142     try {
143       membersInjector.injectMembers(new InjectionFailure());
144       fail();
145     } catch (ProvisionException expected) {
146       assertContains(expected.getMessage(),
147           "1) Error injecting method, java.lang.ClassCastException: whoops, failure #1");
148     }
149   }
150 
testInjectionAppliesToSpecifiedType()151   public void testInjectionAppliesToSpecifiedType() {
152     Injector injector = Guice.createInjector();
153 
154     MembersInjector<Object> membersInjector = injector.getMembersInjector(Object.class);
155     membersInjector.injectMembers(new InjectionFailure());
156   }
157 
testInjectingMembersInjector()158   public void testInjectingMembersInjector() {
159     InjectsMembersInjector injectsMembersInjector = Guice.createInjector(new AbstractModule() {
160       protected void configure() {
161         bind(C.class).toInstance(myFavouriteC);
162       }
163     }).getInstance(InjectsMembersInjector.class);
164 
165     A<C> a = new A<C>();
166     injectsMembersInjector.aMembersInjector.injectMembers(a);
167     assertSame(myFavouriteC, a.t);
168     assertSame(myFavouriteC, a.b.c);
169   }
170 
testCannotBindMembersInjector()171   public void testCannotBindMembersInjector() {
172     try {
173       Guice.createInjector(new AbstractModule() {
174         protected void configure() {
175           bind(MembersInjector.class).toProvider(Providers.<MembersInjector>of(null));
176         }
177       });
178       fail();
179     } catch (CreationException expected) {
180       assertContains(expected.getMessage(),
181           "1) Binding to core guice framework type is not allowed: MembersInjector.");
182     }
183 
184     try {
185       Guice.createInjector(new AbstractModule() {
186         protected void configure() {
187           bind(new TypeLiteral<MembersInjector<A<C>>>() {})
188               .toProvider(Providers.<MembersInjector<A<C>>>of(null));
189         }
190       });
191       fail();
192     } catch (CreationException expected) {
193       assertContains(expected.getMessage(),
194           "1) Binding to core guice framework type is not allowed: MembersInjector.");
195     }
196   }
197 
testInjectingMembersInjectorWithErrorsInDependencies()198   public void testInjectingMembersInjectorWithErrorsInDependencies() {
199     try {
200       Guice.createInjector().getInstance(InjectsBrokenMembersInjector.class);
201       fail();
202     } catch (ConfigurationException expected) {
203       assertContains(expected.getMessage(),
204           "1) No implementation for " + Unimplemented.class.getName() + " was bound.",
205           "while locating " + Unimplemented.class.getName(),
206           "for field at " + A.class.getName() + ".t(MembersInjectorTest.java:",
207           "while locating com.google.inject.MembersInjector<",
208           "for field at " + InjectsBrokenMembersInjector.class.getName() + ".aMembersInjector(",
209           "while locating " + InjectsBrokenMembersInjector.class.getName());
210     }
211   }
212 
testLookupMembersInjectorBinding()213   public void testLookupMembersInjectorBinding() {
214     Injector injector = Guice.createInjector(new AbstractModule() {
215       protected void configure() {
216         bind(C.class).toInstance(myFavouriteC);
217       }
218     });
219     MembersInjector<A<C>> membersInjector =
220         injector.getInstance(new Key<MembersInjector<A<C>>>() {});
221 
222     A<C> a = new A<C>();
223     membersInjector.injectMembers(a);
224     assertSame(myFavouriteC, a.t);
225     assertSame(myFavouriteC, a.b.c);
226 
227     assertEquals("MembersInjector<java.lang.String>",
228         injector.getInstance(new Key<MembersInjector<String>>() {}).toString());
229   }
230 
testGettingRawMembersInjector()231   public void testGettingRawMembersInjector() {
232     Injector injector = Guice.createInjector();
233     try {
234       injector.getInstance(MembersInjector.class);
235       fail();
236     } catch (ConfigurationException expected) {
237       assertContains(expected.getMessage(),
238           "Cannot inject a MembersInjector that has no type parameter");
239     }
240   }
241 
testGettingAnnotatedMembersInjector()242   public void testGettingAnnotatedMembersInjector() {
243     Injector injector = Guice.createInjector();
244     try {
245       injector.getInstance(new Key<MembersInjector<String>>(Names.named("foo")) {});
246       fail();
247     } catch (ConfigurationException expected) {
248       assertContains(expected.getMessage(),
249           "1) No implementation for com.google.inject.MembersInjector<java.lang.String> "
250               + "annotated with @com.google.inject.name.Named(value=foo) was bound.");
251     }
252   }
253 
254   static class A<T> {
255     @Inject B b;
256     @Inject T t;
doNothing()257     @Inject void doNothing() {}
258   }
259 
260   static class B {
261     @Inject C c;
doNothing()262     @Inject void doNothing() {}
263   }
264 
265   static class C {}
266 
267   static class NoInjectedMembers {}
268 
269   static class InjectionFailure {
270     int failures = 0;
271 
fail()272     @Inject void fail() {
273       throw new ClassCastException("whoops, failure #" + (++failures));
274     }
275   }
276 
277   static class InjectsMembersInjector {
278     @Inject MembersInjector<A<C>> aMembersInjector;
279     @Inject A<B> ab;
280   }
281 
282   static class InjectsBrokenMembersInjector {
283     @Inject MembersInjector<A<Unimplemented>> aMembersInjector;
284   }
285 
286   static interface Unimplemented {}
287 }
288