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