• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@google.com (Bob Lee)
33  */
34 public class GenericInjectionTest extends TestCase {
35 
testGenericInjection()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    */
testImplicitBindingOfGenericType()58   public void testImplicitBindingOfGenericType() {
59     Parameterized<String> parameterized
60         = Guice.createInjector().getInstance(Key.get(new TypeLiteral<Parameterized<String>>() {}));
61     assertNotNull(parameterized);
62   }
63 
testExplicitBindingOfGenericType()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
Parameterized()79     Parameterized() { }
80   }
81 
testInjectingParameterizedDependenciesForImplicitBinding()82   public void testInjectingParameterizedDependenciesForImplicitBinding() {
83     assertParameterizedDepsInjected(new Key<ParameterizedDeps<String, Integer>>() {},
84         Modules.EMPTY_MODULE);
85   }
86 
testInjectingParameterizedDependenciesForBindingTarget()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 
testInjectingParameterizedDependenciesForBindingSource()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 
testBindingToSubtype()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 
testBindingSubtype()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")
assertParameterizedDepsInjected(Key<?> key, Module bindingModule)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> {
SubParameterizedDeps(Set<A> keys)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 
ParameterizedDeps(Set<K> keys)165     @Inject ParameterizedDeps(Set<K> keys) {
166       this.keys = keys;
167     }
168 
method(Collection<V> values)169     @Inject void method(Collection<V> values) {
170       this.values = values;
171     }
172   }
173 
testImmediateTypeVariablesAreInjected()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