Home | History | Annotate | Download | only in inject
      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 (at) 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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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;
    257     @Inject void doNothing() {}
    258   }
    259 
    260   static class B {
    261     @Inject C c;
    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 
    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