/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.inject; import static com.google.inject.Asserts.assertContains; import static com.google.inject.Asserts.getDeclaringSourcePart; import static java.lang.annotation.RetentionPolicy.RUNTIME; import com.google.inject.matcher.Matchers; import com.google.inject.spi.TypeEncounter; import com.google.inject.spi.TypeListener; import java.lang.annotation.Retention; import junit.framework.TestCase; /** @author crazybob@google.com (Bob Lee) */ public class RequestInjectionTest extends TestCase { @Retention(RUNTIME) @BindingAnnotation @interface ForField {} @Retention(RUNTIME) @BindingAnnotation @interface ForMethod {} @Override protected void setUp() throws Exception { super.setUp(); HasInjections.staticField = 0; HasInjections.staticMethod = null; } public void testInjectMembers() { final HasInjections hi = new HasInjections(); Guice.createInjector( new AbstractModule() { @Override protected void configure() { bindConstant().annotatedWith(ForMethod.class).to("test"); bindConstant().annotatedWith(ForField.class).to(5); requestInjection(hi); } }); assertEquals("test", hi.instanceMethod); assertEquals(5, hi.instanceField); assertNull(HasInjections.staticMethod); assertEquals(0, HasInjections.staticField); } public void testInjectStatics() throws CreationException { Guice.createInjector( new AbstractModule() { @Override protected void configure() { bindConstant().annotatedWith(ForMethod.class).to("test"); bindConstant().annotatedWith(ForField.class).to(5); requestStaticInjection(HasInjections.class); } }); assertEquals("test", HasInjections.staticMethod); assertEquals(5, HasInjections.staticField); } public void testInjectMembersAndStatics() { final HasInjections hi = new HasInjections(); Guice.createInjector( new AbstractModule() { @Override protected void configure() { bindConstant().annotatedWith(ForMethod.class).to("test"); bindConstant().annotatedWith(ForField.class).to(5); requestStaticInjection(HasInjections.class); requestInjection(hi); } }); assertEquals("test", hi.instanceMethod); assertEquals(5, hi.instanceField); assertEquals("test", HasInjections.staticMethod); assertEquals(5, HasInjections.staticField); } public void testValidationErrorOnInjectedMembers() { try { Guice.createInjector( new AbstractModule() { @Override protected void configure() { requestInjection(new NeedsRunnable()); } }); fail("Expected CreationException"); } catch (CreationException expected) { assertContains( expected.getMessage(), "1) No implementation for java.lang.Runnable was bound", "at " + NeedsRunnable.class.getName(), ".runnable(RequestInjectionTest.java:"); } } public void testInjectionErrorOnInjectedMembers() { try { Guice.createInjector( new AbstractModule() { @Override protected void configure() { bind(Runnable.class) .toProvider( new Provider<Runnable>() { @Override public Runnable get() { throw new UnsupportedOperationException(); } }); requestInjection(new NeedsRunnable()); } }); } catch (CreationException expected) { assertContains( expected.getMessage(), "1) Error in custom provider, java.lang.UnsupportedOperationException", "for field at " + NeedsRunnable.class.getName() + ".runnable(RequestInjectionTest.java:", "at " + getClass().getName(), getDeclaringSourcePart(getClass())); } } public void testUserExceptionWhileInjectingInstance() { try { Guice.createInjector( new AbstractModule() { @Override protected void configure() { requestInjection(new BlowsUpOnInject()); } }); fail(); } catch (CreationException expected) { assertContains( expected.getMessage(), "1) Error injecting method, java.lang.UnsupportedOperationException: Pop", "at " + BlowsUpOnInject.class.getName() + ".injectInstance(RequestInjectionTest.java:"); } } public void testUserExceptionWhileInjectingStatically() { try { Guice.createInjector( new AbstractModule() { @Override protected void configure() { requestStaticInjection(BlowsUpOnInject.class); } }); fail(); } catch (CreationException expected) { assertContains( expected.getMessage(), "1) Error injecting method, java.lang.UnsupportedOperationException: Snap", "at " + BlowsUpOnInject.class.getName() + ".injectStatically(RequestInjectionTest.java:"); } } static class NeedsRunnable { @Inject Runnable runnable; } static class HasInjections { @Inject @ForField static int staticField; @Inject @ForField int instanceField; static String staticMethod; String instanceMethod; @Inject static void setStaticMethod(@ForMethod String staticMethod) { HasInjections.staticMethod = staticMethod; } @Inject void setInstanceS(@ForMethod String instanceS) { this.instanceMethod = instanceS; } } static class BlowsUpOnInject { @Inject void injectInstance() { throw new UnsupportedOperationException("Pop"); } @Inject static void injectStatically() { throw new UnsupportedOperationException("Snap"); } } /* * Tests that initializables of the same instance don't clobber * membersInjectors in InitializableReference, so that they ultimately * can be requested in any order. */ public void testEarlyInjectableReferencesWithSameIdentity() { Injector injector = Guice.createInjector( new AbstractModule() { @Override protected void configure() { // Add a listener to trigger all toInstance bindings to get an Initializable. bindListener( Matchers.any(), new TypeListener() { @Override public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {} }); // Bind two different Keys to the IDENTITICAL object // ORDER MATTERS! We want the String binding to push out the Object one String fail = new String("better not fail!"); bind(Object.class).toInstance(fail); bind(String.class).toInstance(fail); // Then try to inject those objects in a requestInjection, // letting us get into InjectableReference.get before it has // finished running through all its injections. // Each of these technically has its own InjectableReference internally. // ORDER MATTERS!.. because Object is injected first, that InjectableReference // attempts to process its members injector, but it wasn't initialized, // because String pushed it out of the queue! requestInjection( new Object() { @SuppressWarnings("unused") @Inject Object obj; @SuppressWarnings("unused") @Inject String str; }); } }); } }