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