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 
     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