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