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.Asserts.assertContains; 20 import static com.google.inject.Asserts.getDeclaringSourcePart; 21 import static java.lang.annotation.RetentionPolicy.RUNTIME; 22 23 import com.google.inject.matcher.Matchers; 24 import com.google.inject.spi.TypeEncounter; 25 import com.google.inject.spi.TypeListener; 26 import java.lang.annotation.Retention; 27 import junit.framework.TestCase; 28 29 /** @author crazybob@google.com (Bob Lee) */ 30 public class RequestInjectionTest extends TestCase { 31 32 @Retention(RUNTIME) 33 @BindingAnnotation 34 @interface ForField {} 35 36 @Retention(RUNTIME) 37 @BindingAnnotation 38 @interface ForMethod {} 39 40 @Override setUp()41 protected void setUp() throws Exception { 42 super.setUp(); 43 HasInjections.staticField = 0; 44 HasInjections.staticMethod = null; 45 } 46 testInjectMembers()47 public void testInjectMembers() { 48 final HasInjections hi = new HasInjections(); 49 50 Guice.createInjector( 51 new AbstractModule() { 52 @Override 53 protected void configure() { 54 bindConstant().annotatedWith(ForMethod.class).to("test"); 55 bindConstant().annotatedWith(ForField.class).to(5); 56 requestInjection(hi); 57 } 58 }); 59 60 assertEquals("test", hi.instanceMethod); 61 assertEquals(5, hi.instanceField); 62 assertNull(HasInjections.staticMethod); 63 assertEquals(0, HasInjections.staticField); 64 } 65 testInjectStatics()66 public void testInjectStatics() throws CreationException { 67 Guice.createInjector( 68 new AbstractModule() { 69 @Override 70 protected void configure() { 71 bindConstant().annotatedWith(ForMethod.class).to("test"); 72 bindConstant().annotatedWith(ForField.class).to(5); 73 requestStaticInjection(HasInjections.class); 74 } 75 }); 76 77 assertEquals("test", HasInjections.staticMethod); 78 assertEquals(5, HasInjections.staticField); 79 } 80 testInjectMembersAndStatics()81 public void testInjectMembersAndStatics() { 82 final HasInjections hi = new HasInjections(); 83 84 Guice.createInjector( 85 new AbstractModule() { 86 @Override 87 protected void configure() { 88 bindConstant().annotatedWith(ForMethod.class).to("test"); 89 bindConstant().annotatedWith(ForField.class).to(5); 90 requestStaticInjection(HasInjections.class); 91 requestInjection(hi); 92 } 93 }); 94 95 assertEquals("test", hi.instanceMethod); 96 assertEquals(5, hi.instanceField); 97 assertEquals("test", HasInjections.staticMethod); 98 assertEquals(5, HasInjections.staticField); 99 } 100 testValidationErrorOnInjectedMembers()101 public void testValidationErrorOnInjectedMembers() { 102 try { 103 Guice.createInjector( 104 new AbstractModule() { 105 @Override 106 protected void configure() { 107 requestInjection(new NeedsRunnable()); 108 } 109 }); 110 fail("Expected CreationException"); 111 } catch (CreationException expected) { 112 assertContains( 113 expected.getMessage(), 114 "1) No implementation for java.lang.Runnable was bound", 115 "at " + NeedsRunnable.class.getName(), 116 ".runnable(RequestInjectionTest.java:"); 117 } 118 } 119 testInjectionErrorOnInjectedMembers()120 public void testInjectionErrorOnInjectedMembers() { 121 try { 122 Guice.createInjector( 123 new AbstractModule() { 124 @Override 125 protected void configure() { 126 bind(Runnable.class) 127 .toProvider( 128 new Provider<Runnable>() { 129 @Override 130 public Runnable get() { 131 throw new UnsupportedOperationException(); 132 } 133 }); 134 requestInjection(new NeedsRunnable()); 135 } 136 }); 137 } catch (CreationException expected) { 138 assertContains( 139 expected.getMessage(), 140 "1) Error in custom provider, java.lang.UnsupportedOperationException", 141 "for field at " + NeedsRunnable.class.getName() + ".runnable(RequestInjectionTest.java:", 142 "at " + getClass().getName(), 143 getDeclaringSourcePart(getClass())); 144 } 145 } 146 testUserExceptionWhileInjectingInstance()147 public void testUserExceptionWhileInjectingInstance() { 148 try { 149 Guice.createInjector( 150 new AbstractModule() { 151 @Override 152 protected void configure() { 153 requestInjection(new BlowsUpOnInject()); 154 } 155 }); 156 fail(); 157 } catch (CreationException expected) { 158 assertContains( 159 expected.getMessage(), 160 "1) Error injecting method, java.lang.UnsupportedOperationException: Pop", 161 "at " + BlowsUpOnInject.class.getName() + ".injectInstance(RequestInjectionTest.java:"); 162 } 163 } 164 testUserExceptionWhileInjectingStatically()165 public void testUserExceptionWhileInjectingStatically() { 166 try { 167 Guice.createInjector( 168 new AbstractModule() { 169 @Override 170 protected void configure() { 171 requestStaticInjection(BlowsUpOnInject.class); 172 } 173 }); 174 fail(); 175 } catch (CreationException expected) { 176 assertContains( 177 expected.getMessage(), 178 "1) Error injecting method, java.lang.UnsupportedOperationException: Snap", 179 "at " + BlowsUpOnInject.class.getName() + ".injectStatically(RequestInjectionTest.java:"); 180 } 181 } 182 183 static class NeedsRunnable { 184 @Inject Runnable runnable; 185 } 186 187 static class HasInjections { 188 189 @Inject @ForField static int staticField; 190 @Inject @ForField int instanceField; 191 192 static String staticMethod; 193 String instanceMethod; 194 195 @Inject setStaticMethod(@orMethod String staticMethod)196 static void setStaticMethod(@ForMethod String staticMethod) { 197 HasInjections.staticMethod = staticMethod; 198 } 199 200 @Inject setInstanceS(@orMethod String instanceS)201 void setInstanceS(@ForMethod String instanceS) { 202 this.instanceMethod = instanceS; 203 } 204 } 205 206 static class BlowsUpOnInject { 207 @Inject injectInstance()208 void injectInstance() { 209 throw new UnsupportedOperationException("Pop"); 210 } 211 212 @Inject injectStatically()213 static void injectStatically() { 214 throw new UnsupportedOperationException("Snap"); 215 } 216 } 217 218 /* 219 * Tests that initializables of the same instance don't clobber 220 * membersInjectors in InitializableReference, so that they ultimately 221 * can be requested in any order. 222 */ testEarlyInjectableReferencesWithSameIdentity()223 public void testEarlyInjectableReferencesWithSameIdentity() { 224 Injector injector = 225 Guice.createInjector( 226 new AbstractModule() { 227 @Override 228 protected void configure() { 229 // Add a listener to trigger all toInstance bindings to get an Initializable. 230 bindListener( 231 Matchers.any(), 232 new TypeListener() { 233 @Override 234 public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {} 235 }); 236 237 // Bind two different Keys to the IDENTITICAL object 238 // ORDER MATTERS! We want the String binding to push out the Object one 239 String fail = new String("better not fail!"); 240 bind(Object.class).toInstance(fail); 241 bind(String.class).toInstance(fail); 242 243 // Then try to inject those objects in a requestInjection, 244 // letting us get into InjectableReference.get before it has 245 // finished running through all its injections. 246 // Each of these technically has its own InjectableReference internally. 247 // ORDER MATTERS!.. because Object is injected first, that InjectableReference 248 // attempts to process its members injector, but it wasn't initialized, 249 // because String pushed it out of the queue! 250 requestInjection( 251 new Object() { 252 @SuppressWarnings("unused") 253 @Inject 254 Object obj; 255 256 @SuppressWarnings("unused") 257 @Inject 258 String str; 259 }); 260 } 261 }); 262 } 263 } 264