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