/core/test/com/google/inject/MembersInjectorTest.java
Java | 401 lines | 302 code | 67 blank | 32 comment | 3 complexity | 4bb85b1a0a5173d81b149e564c8020b3 MD5 | raw file
- /**
- * Copyright (C) 2009 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 com.google.inject.name.Names;
- import com.google.inject.util.Providers;
- import junit.framework.AssertionFailedError;
- import junit.framework.TestCase;
- import java.util.concurrent.Callable;
- import java.util.concurrent.Executors;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.TimeoutException;
- import java.util.concurrent.atomic.AtomicReference;
- /**
- * @author jessewilson@google.com (Jesse Wilson)
- */
- public class MembersInjectorTest extends TestCase {
- private static final long DEADLOCK_TIMEOUT_SECONDS = 1;
- private static final A<C> uninjectableA = new A<C>() {
- @Override void doNothing() {
- throw new AssertionFailedError();
- }
- };
- private static final B uninjectableB = new B() {
- @Override void doNothing() {
- throw new AssertionFailedError();
- }
- };
- private static final C myFavouriteC = new C();
- public void testMembersInjectorFromBinder() {
- final AtomicReference<MembersInjector<A<C>>> aMembersInjectorReference
- = new AtomicReference<MembersInjector<A<C>>>();
- final AtomicReference<MembersInjector<B>> bMembersInjectorReference
- = new AtomicReference<MembersInjector<B>>();
- Guice.createInjector(new AbstractModule() {
- @Override protected void configure() {
- MembersInjector<A<C>> aMembersInjector = getMembersInjector(new TypeLiteral<A<C>>() {});
- try {
- aMembersInjector.injectMembers(uninjectableA);
- fail();
- } catch (IllegalStateException expected) {
- assertContains(expected.getMessage(),
- "This MembersInjector cannot be used until the Injector has been created.");
- }
- MembersInjector<B> bMembersInjector = getMembersInjector(B.class);
- try {
- bMembersInjector.injectMembers(uninjectableB);
- fail();
- } catch (IllegalStateException expected) {
- assertContains(expected.getMessage(),
- "This MembersInjector cannot be used until the Injector has been created.");
- }
- aMembersInjectorReference.set(aMembersInjector);
- bMembersInjectorReference.set(bMembersInjector);
- assertEquals("MembersInjector<java.lang.String>",
- getMembersInjector(String.class).toString());
- bind(C.class).toInstance(myFavouriteC);
- }
- });
- A<C> injectableA = new A<C>();
- aMembersInjectorReference.get().injectMembers(injectableA);
- assertSame(myFavouriteC, injectableA.t);
- assertSame(myFavouriteC, injectableA.b.c);
- B injectableB = new B();
- bMembersInjectorReference.get().injectMembers(injectableB);
- assertSame(myFavouriteC, injectableB.c);
- B anotherInjectableB = new B();
- bMembersInjectorReference.get().injectMembers(anotherInjectableB);
- assertSame(myFavouriteC, anotherInjectableB.c);
- }
- public void testMembersInjectorFromInjector() {
- Injector injector = Guice.createInjector(new AbstractModule() {
- protected void configure() {
- bind(C.class).toInstance(myFavouriteC);
- }
- });
- MembersInjector<A<C>> aMembersInjector
- = injector.getMembersInjector(new TypeLiteral<A<C>>() {});
- MembersInjector<B> bMembersInjector = injector.getMembersInjector(B.class);
- A<C> injectableA = new A<C>();
- aMembersInjector.injectMembers(injectableA);
- assertSame(myFavouriteC, injectableA.t);
- assertSame(myFavouriteC, injectableA.b.c);
- B injectableB = new B();
- bMembersInjector.injectMembers(injectableB);
- assertSame(myFavouriteC, injectableB.c);
- B anotherInjectableB = new B();
- bMembersInjector.injectMembers(anotherInjectableB);
- assertSame(myFavouriteC, anotherInjectableB.c);
- assertEquals("MembersInjector<java.lang.String>",
- injector.getMembersInjector(String.class).toString());
- }
- public void testMembersInjectorWithNonInjectedTypes() {
- Injector injector = Guice.createInjector();
- MembersInjector<NoInjectedMembers> membersInjector
- = injector.getMembersInjector(NoInjectedMembers.class);
- membersInjector.injectMembers(new NoInjectedMembers());
- membersInjector.injectMembers(new NoInjectedMembers());
- }
- public void testInjectionFailure() {
- Injector injector = Guice.createInjector();
- MembersInjector<InjectionFailure> membersInjector
- = injector.getMembersInjector(InjectionFailure.class);
- try {
- membersInjector.injectMembers(new InjectionFailure());
- fail();
- } catch (ProvisionException expected) {
- assertContains(expected.getMessage(),
- "1) Error injecting method, java.lang.ClassCastException: whoops, failure #1");
- }
- }
- public void testInjectionAppliesToSpecifiedType() {
- Injector injector = Guice.createInjector();
- MembersInjector<Object> membersInjector = injector.getMembersInjector(Object.class);
- membersInjector.injectMembers(new InjectionFailure());
- }
- public void testInjectingMembersInjector() {
- InjectsMembersInjector injectsMembersInjector = Guice.createInjector(new AbstractModule() {
- protected void configure() {
- bind(C.class).toInstance(myFavouriteC);
- }
- }).getInstance(InjectsMembersInjector.class);
- A<C> a = new A<C>();
- injectsMembersInjector.aMembersInjector.injectMembers(a);
- assertSame(myFavouriteC, a.t);
- assertSame(myFavouriteC, a.b.c);
- }
- public void testCannotBindMembersInjector() {
- try {
- Guice.createInjector(new AbstractModule() {
- protected void configure() {
- bind(MembersInjector.class).toProvider(Providers.<MembersInjector>of(null));
- }
- });
- fail();
- } catch (CreationException expected) {
- assertContains(expected.getMessage(),
- "1) Binding to core guice framework type is not allowed: MembersInjector.");
- }
- try {
- Guice.createInjector(new AbstractModule() {
- protected void configure() {
- bind(new TypeLiteral<MembersInjector<A<C>>>() {})
- .toProvider(Providers.<MembersInjector<A<C>>>of(null));
- }
- });
- fail();
- } catch (CreationException expected) {
- assertContains(expected.getMessage(),
- "1) Binding to core guice framework type is not allowed: MembersInjector.");
- }
- }
- public void testInjectingMembersInjectorWithErrorsInDependencies() {
- try {
- Guice.createInjector().getInstance(InjectsBrokenMembersInjector.class);
- fail();
- } catch (ConfigurationException expected) {
- assertContains(expected.getMessage(),
- "1) No implementation for " + Unimplemented.class.getName() + " was bound.",
- "while locating " + Unimplemented.class.getName(),
- "for field at " + A.class.getName() + ".t(MembersInjectorTest.java:",
- "while locating com.google.inject.MembersInjector<",
- "for field at " + InjectsBrokenMembersInjector.class.getName() + ".aMembersInjector(",
- "while locating " + InjectsBrokenMembersInjector.class.getName());
- }
- }
- public void testLookupMembersInjectorBinding() {
- Injector injector = Guice.createInjector(new AbstractModule() {
- protected void configure() {
- bind(C.class).toInstance(myFavouriteC);
- }
- });
- MembersInjector<A<C>> membersInjector =
- injector.getInstance(new Key<MembersInjector<A<C>>>() {});
- A<C> a = new A<C>();
- membersInjector.injectMembers(a);
- assertSame(myFavouriteC, a.t);
- assertSame(myFavouriteC, a.b.c);
- assertEquals("MembersInjector<java.lang.String>",
- injector.getInstance(new Key<MembersInjector<String>>() {}).toString());
- }
- public void testGettingRawMembersInjector() {
- Injector injector = Guice.createInjector();
- try {
- injector.getInstance(MembersInjector.class);
- fail();
- } catch (ConfigurationException expected) {
- assertContains(expected.getMessage(),
- "Cannot inject a MembersInjector that has no type parameter");
- }
- }
- public void testGettingAnnotatedMembersInjector() {
- Injector injector = Guice.createInjector();
- try {
- injector.getInstance(new Key<MembersInjector<String>>(Names.named("foo")) {});
- fail();
- } catch (ConfigurationException expected) {
- assertContains(expected.getMessage(),
- "1) No implementation for com.google.inject.MembersInjector<java.lang.String> "
- + "annotated with @com.google.inject.name.Named(value=foo) was bound.");
- }
- }
- /** Callback for member injection. Uses a static type to be referable by getInstance(). */
- abstract static class AbstractParallelMemberInjectionCallback {
- volatile boolean called = false;
- private final Thread mainThread;
- private final Class<? extends AbstractParallelMemberInjectionCallback> otherCallbackClass;
- AbstractParallelMemberInjectionCallback(
- Class<? extends AbstractParallelMemberInjectionCallback> otherCallbackClass) {
- this.mainThread = Thread.currentThread();
- this.otherCallbackClass = otherCallbackClass;
- }
- @Inject void callback(final Injector injector) throws Exception {
- called = true;
- if (mainThread != Thread.currentThread()) {
- // only execute logic on the main thread
- return;
- }
- // verify that other callback can be finished on a separate thread
- AbstractParallelMemberInjectionCallback otherCallback = Executors
- .newSingleThreadExecutor()
- .submit(new Callable<AbstractParallelMemberInjectionCallback>() {
- @Override
- public AbstractParallelMemberInjectionCallback call() throws Exception {
- return injector.getInstance(otherCallbackClass);
- }
- }).get(DEADLOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- assertTrue(otherCallback.called);
- try {
- // other thread would wait for callback to finish on this thread first
- Executors.newSingleThreadExecutor()
- .submit(new Callable<Object>() {
- @Override
- public Object call() throws Exception {
- return injector.getInstance(
- AbstractParallelMemberInjectionCallback.this.getClass());
- }
- }).get(DEADLOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
- fail();
- } catch (TimeoutException expected) {
- // recursive call from another thread should time out
- // as it would be waiting for this thread to finish
- }
- }
- }
- static class ParallelMemberInjectionCallback1 extends AbstractParallelMemberInjectionCallback {
- ParallelMemberInjectionCallback1() {
- super(ParallelMemberInjectionCallback2.class);
- }
- }
- static class ParallelMemberInjectionCallback2 extends AbstractParallelMemberInjectionCallback {
- ParallelMemberInjectionCallback2() {
- super(ParallelMemberInjectionCallback1.class);
- }
- }
- /**
- * Tests that member injections could happen in parallel.
- *
- * <p>Additional check that when member injection happen other threads would wait for
- * it to finish to provide proper resolution order semantics.
- */
- public void testMemberInjectorParallelization() throws Exception {
- final ParallelMemberInjectionCallback1 c1 = new ParallelMemberInjectionCallback1();
- final ParallelMemberInjectionCallback2 c2 = new ParallelMemberInjectionCallback2();
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(ParallelMemberInjectionCallback1.class).toInstance(c1);
- bind(ParallelMemberInjectionCallback2.class).toInstance(c2);
- }
- });
- assertTrue(c1.called);
- assertTrue(c2.called);
- }
- /** Member injection callback that injects itself. */
- static class RecursiveMemberInjection {
- boolean called = false;
- @Inject void callback(RecursiveMemberInjection recursiveMemberInjection) {
- if (called) {
- fail("Should not be called twice");
- }
- called = true;
- }
- }
- /** Verifies that member injection injecting itself would get a non initialized instance. */
- public void testRecursiveMemberInjector() throws Exception {
- final RecursiveMemberInjection rmi = new RecursiveMemberInjection();
- Guice.createInjector(new AbstractModule() {
- @Override
- protected void configure() {
- bind(RecursiveMemberInjection.class).toInstance(rmi);
- }
- });
- assertTrue("Member injection should happen", rmi.called);
- }
- static class A<T> {
- @Inject B b;
- @Inject T t;
- @Inject void doNothing() {}
- }
- static class B {
- @Inject C c;
- @Inject void doNothing() {}
- }
- static class C {}
- static class NoInjectedMembers {}
- static class InjectionFailure {
- int failures = 0;
- @Inject void fail() {
- throw new ClassCastException("whoops, failure #" + (++failures));
- }
- }
- static class InjectsMembersInjector {
- @Inject MembersInjector<A<C>> aMembersInjector;
- @Inject A<B> ab;
- }
- static class InjectsBrokenMembersInjector {
- @Inject MembersInjector<A<Unimplemented>> aMembersInjector;
- }
- static interface Unimplemented {}
- }