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 com.google.common.collect.ImmutableMap;
     20 import com.google.common.collect.ImmutableSet;
     21 import com.google.inject.util.Modules;
     22 
     23 import junit.framework.TestCase;
     24 
     25 import java.util.Arrays;
     26 import java.util.Collection;
     27 import java.util.List;
     28 import java.util.Map;
     29 import java.util.Set;
     30 
     31 /**
     32  * @author crazybob (at) google.com (Bob Lee)
     33  */
     34 public class GenericInjectionTest extends TestCase {
     35 
     36   public void testGenericInjection() throws CreationException {
     37     final List<String> names = Arrays.asList("foo", "bar", "bob");
     38 
     39     Injector injector = Guice.createInjector((Module) new AbstractModule() {
     40       protected void configure() {
     41         bind(new TypeLiteral<List<String>>() {}).toInstance(names);
     42       }
     43     });
     44 
     45     Foo foo = injector.getInstance(Foo.class);
     46     assertEquals(names, foo.names);
     47   }
     48 
     49   static class Foo {
     50     @Inject List<String> names;
     51   }
     52 
     53   /**
     54    * Although we may not have intended to support this behaviour, this test
     55    * passes under Guice 1.0. The workaround is to add an explicit binding for
     56    * the parameterized type. See {@link #testExplicitBindingOfGenericType()}.
     57    */
     58   public void testImplicitBindingOfGenericType() {
     59     Parameterized<String> parameterized
     60         = Guice.createInjector().getInstance(Key.get(new TypeLiteral<Parameterized<String>>() {}));
     61     assertNotNull(parameterized);
     62   }
     63 
     64   public void testExplicitBindingOfGenericType() {
     65     Injector injector = Guice.createInjector(new AbstractModule() {
     66       protected void configure() {
     67         bind(Key.get(new TypeLiteral<Parameterized<String>>() {}))
     68             .to((Class) Parameterized.class);
     69       }
     70     });
     71 
     72     Parameterized<String> parameterized
     73         = injector.getInstance(Key.get(new TypeLiteral<Parameterized<String>>() { }));
     74     assertNotNull(parameterized);
     75   }
     76 
     77   static class Parameterized<T> {
     78     @Inject
     79     Parameterized() { }
     80   }
     81 
     82   public void testInjectingParameterizedDependenciesForImplicitBinding() {
     83     assertParameterizedDepsInjected(new Key<ParameterizedDeps<String, Integer>>() {},
     84         Modules.EMPTY_MODULE);
     85   }
     86 
     87   public void testInjectingParameterizedDependenciesForBindingTarget() {
     88     final TypeLiteral<ParameterizedDeps<String, Integer>> type
     89         = new TypeLiteral<ParameterizedDeps<String, Integer>>() {};
     90 
     91     assertParameterizedDepsInjected(Key.get(Object.class), new AbstractModule() {
     92       protected void configure() {
     93         bind(Object.class).to(type);
     94       }
     95     });
     96   }
     97 
     98   public void testInjectingParameterizedDependenciesForBindingSource() {
     99     final TypeLiteral<ParameterizedDeps<String, Integer>> type
    100         = new TypeLiteral<ParameterizedDeps<String, Integer>>() {};
    101 
    102     assertParameterizedDepsInjected(Key.get(type), new AbstractModule() {
    103       protected void configure() {
    104         bind(type);
    105       }
    106     });
    107   }
    108 
    109   public void testBindingToSubtype() {
    110     final TypeLiteral<ParameterizedDeps<String, Integer>> type
    111         = new TypeLiteral<ParameterizedDeps<String, Integer>>() {};
    112 
    113     assertParameterizedDepsInjected(Key.get(type), new AbstractModule() {
    114       protected void configure() {
    115         bind(type).to(new TypeLiteral<SubParameterizedDeps<String, Long, Integer>>() {});
    116       }
    117     });
    118   }
    119 
    120   public void testBindingSubtype() {
    121     final TypeLiteral<SubParameterizedDeps<String, Long, Integer>> type
    122         = new TypeLiteral<SubParameterizedDeps<String, Long, Integer>>() {};
    123 
    124     assertParameterizedDepsInjected(Key.get(type), new AbstractModule() {
    125       protected void configure() {
    126         bind(type);
    127       }
    128     });
    129   }
    130 
    131   @SuppressWarnings("unchecked")
    132   public void assertParameterizedDepsInjected(Key<?> key, Module bindingModule) {
    133     Module bindDataModule = new AbstractModule() {
    134       protected void configure() {}
    135       @Provides Map<String, Integer> provideMap() {
    136         return ImmutableMap.of("one", 1, "two", 2);
    137       }
    138       @Provides Set<String> provideSet(Map<String, Integer> map) {
    139         return map.keySet();
    140       }
    141       @Provides Collection<Integer> provideCollection(Map<String, Integer> map) {
    142         return map.values();
    143       }
    144     };
    145 
    146     Injector injector = Guice.createInjector(bindDataModule, bindingModule);
    147     ParameterizedDeps<String, Integer> parameterizedDeps
    148         = (ParameterizedDeps<String, Integer>) injector.getInstance(key);
    149     assertEquals(ImmutableMap.of("one", 1, "two", 2), parameterizedDeps.map);
    150     assertEquals(ImmutableSet.of("one", "two"), parameterizedDeps.keys);
    151     assertEquals(ImmutableSet.of(1, 2), ImmutableSet.copyOf(parameterizedDeps.values));
    152   }
    153 
    154   static class SubParameterizedDeps<A, B, C> extends ParameterizedDeps<A, C> {
    155     @Inject SubParameterizedDeps(Set<A> keys) {
    156       super(keys);
    157     }
    158   }
    159 
    160   static class ParameterizedDeps<K, V> {
    161     @Inject private Map<K, V> map;
    162     private Set<K> keys;
    163     private Collection<V> values;
    164 
    165     @Inject ParameterizedDeps(Set<K> keys) {
    166       this.keys = keys;
    167     }
    168 
    169     @Inject void method(Collection<V> values) {
    170       this.values = values;
    171     }
    172   }
    173 
    174   public void testImmediateTypeVariablesAreInjected() {
    175     Injector injector = Guice.createInjector(new AbstractModule() {
    176       protected void configure() {
    177         bind(String.class).toInstance("tee");
    178       }
    179     });
    180     InjectsT<String> injectsT = injector.getInstance(new Key<InjectsT<String>>() {});
    181     assertEquals("tee", injectsT.t);
    182   }
    183 
    184   static class InjectsT<T> {
    185     @Inject T t;
    186   }
    187 }
    188