Home | History | Annotate | Download | only in inject
      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 (at) 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
     41   protected void setUp() throws Exception {
     42     super.setUp();
     43     HasInjections.staticField = 0;
     44     HasInjections.staticMethod = null;
     45   }
     46 
     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 
     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 
     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 
    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 
    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 
    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 
    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
    196     static void setStaticMethod(@ForMethod String staticMethod) {
    197       HasInjections.staticMethod = staticMethod;
    198     }
    199 
    200     @Inject
    201     void setInstanceS(@ForMethod String instanceS) {
    202       this.instanceMethod = instanceS;
    203     }
    204   }
    205 
    206   static class BlowsUpOnInject {
    207     @Inject
    208     void injectInstance() {
    209       throw new UnsupportedOperationException("Pop");
    210     }
    211 
    212     @Inject
    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    */
    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