diff --git a/src/main/java/org/springframework/guice/module/BindingTypeMatcher.java b/src/main/java/org/springframework/guice/module/BindingTypeMatcher.java index f71818f..4ad7791 100644 --- a/src/main/java/org/springframework/guice/module/BindingTypeMatcher.java +++ b/src/main/java/org/springframework/guice/module/BindingTypeMatcher.java @@ -16,12 +16,14 @@ package org.springframework.guice.module; +import java.lang.reflect.Type; + /** * @author Dave Syer * */ public interface BindingTypeMatcher { - boolean matches(String name, Class type); + boolean matches(String name, Type type); } diff --git a/src/main/java/org/springframework/guice/module/GuiceModuleMetadata.java b/src/main/java/org/springframework/guice/module/GuiceModuleMetadata.java index a3567d4..2f61201 100644 --- a/src/main/java/org/springframework/guice/module/GuiceModuleMetadata.java +++ b/src/main/java/org/springframework/guice/module/GuiceModuleMetadata.java @@ -18,12 +18,14 @@ package org.springframework.guice.module; import java.io.IOException; import java.lang.reflect.Modifier; +import java.lang.reflect.Type; import java.util.HashSet; import java.util.Set; import java.util.regex.Pattern; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.ResolvableType; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; @@ -93,7 +95,7 @@ public class GuiceModuleMetadata implements BindingTypeMatcher { } @Override - public boolean matches(String name, Class type) { + public boolean matches(String name, Type type) { if (!matches(name) || !matches(type)) { return false; } @@ -128,7 +130,7 @@ public class GuiceModuleMetadata implements BindingTypeMatcher { return true; } - private boolean matches(Class type) { + private boolean matches(Type type) { if (infrastructureTypes.contains(type)) { return false; } @@ -140,7 +142,7 @@ public class GuiceModuleMetadata implements BindingTypeMatcher { if (includeFilters != null) { try { MetadataReader reader = metadataReaderFactory.getMetadataReader(type - .getName()); + .getTypeName()); for (TypeFilter filter : includeFilters) { if (!filter.match(reader, metadataReaderFactory)) { return false; @@ -154,7 +156,7 @@ public class GuiceModuleMetadata implements BindingTypeMatcher { if (excludeFilters != null) { try { MetadataReader reader = metadataReaderFactory.getMetadataReader(type - .getName()); + .getTypeName()); for (TypeFilter filter : excludeFilters) { if (filter.match(reader, metadataReaderFactory)) { return false; @@ -168,8 +170,8 @@ public class GuiceModuleMetadata implements BindingTypeMatcher { return true; } - private boolean visible(Class type) { - Class cls = type; + private boolean visible(Type type) { + Class cls = ResolvableType.forType(type).resolve(); while (cls != null && cls != Object.class) { if (!Modifier.isInterface(cls.getModifiers()) && !Modifier.isPublic(cls.getModifiers()) diff --git a/src/main/java/org/springframework/guice/module/SpringModule.java b/src/main/java/org/springframework/guice/module/SpringModule.java index c12ae3d..0d2769c 100644 --- a/src/main/java/org/springframework/guice/module/SpringModule.java +++ b/src/main/java/org/springframework/guice/module/SpringModule.java @@ -13,6 +13,7 @@ package org.springframework.guice.module; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -28,8 +29,10 @@ import org.springframework.util.ClassUtils; import com.google.inject.Binder; import com.google.inject.Module; +import com.google.inject.Key; import com.google.inject.Provider; import com.google.inject.ProvisionException; +import com.google.inject.TypeLiteral; import com.google.inject.name.Names; /** @@ -42,7 +45,7 @@ public class SpringModule implements Module { private BindingTypeMatcher matcher = new GuiceModuleMetadata(); - private Map, Provider> bound = new HashMap, Provider>(); + private Map> bound = new HashMap>(); public SpringModule(ApplicationContext context) { this((DefaultListableBeanFactory) context.getAutowireCapableBeanFactory()); @@ -55,64 +58,65 @@ public class SpringModule implements Module { } } - @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) public void configure(Binder binder) { for (String name : this.beanFactory.getBeanDefinitionNames()) { BeanDefinition definition = this.beanFactory.getBeanDefinition(name); if (definition.isAutowireCandidate() && definition.getRole() == AbstractBeanDefinition.ROLE_APPLICATION) { Class type = this.beanFactory.getType(name); - @SuppressWarnings("unchecked") - final Class cls = (Class) type; final String beanName = name; Provider typeProvider = new BeanFactoryProvider(this.beanFactory, null, type); Provider namedProvider = new BeanFactoryProvider(this.beanFactory, beanName, type); - if (!cls.isInterface() && !ClassUtils.isCglibProxyClass(cls)) { - bindConditionally(binder, name, cls, typeProvider, namedProvider); + if (!type.isInterface() && !ClassUtils.isCglibProxyClass(type)) { + bindConditionally(binder, name, type, typeProvider, namedProvider); } - for (Class iface : ClassUtils.getAllInterfacesForClass(cls)) { - @SuppressWarnings("unchecked") - Class unchecked = (Class) iface; - bindConditionally(binder, name, unchecked, typeProvider, namedProvider); + for (Class iface : ClassUtils.getAllInterfacesForClass(type)) { + bindConditionally(binder, name, iface, typeProvider, namedProvider); + } + for (Type iface : type.getGenericInterfaces()) { + bindConditionally(binder, name, iface, typeProvider, namedProvider); } } } } - private void bindConditionally(Binder binder, String name, Class type, Provider typeProvider, - Provider namedProvider) { + @SuppressWarnings({ "rawtypes", "unchecked" }) + private void bindConditionally(Binder binder, String name, Type type, Provider typeProvider, + Provider namedProvider) { if (!this.matcher.matches(name, type)) { return; } - if (type.getName().startsWith("com.google.inject")) { + if (type.getTypeName().startsWith("com.google.inject")) { return; } + if (this.bound.get(type) == null) { // Only bind one provider for each type - binder.withSource("spring-guice").bind(type).toProvider(typeProvider); - this.bound.put(type, typeProvider); + binder.withSource("spring-guice").bind(Key.get(type)).toProvider(typeProvider); + this.bound.put(type, typeProvider); } // But allow binding to named beans - binder.withSource("spring-guice").bind(type).annotatedWith(Names.named(name)).toProvider(namedProvider); + binder.withSource("spring-guice").bind(TypeLiteral.get(type)).annotatedWith(Names.named(name)).toProvider(namedProvider); } - private static class BeanFactoryProvider implements Provider { + private static class BeanFactoryProvider implements Provider { private DefaultListableBeanFactory beanFactory; private String name; - private Class type; + private Class type; - private Object result; + private T result; - public BeanFactoryProvider(DefaultListableBeanFactory beanFactory, String name, Class type) { + public BeanFactoryProvider(DefaultListableBeanFactory beanFactory, String name, Class type) { this.beanFactory = beanFactory; this.name = name; this.type = type; } @Override - public Object get() { + public T get() { if (this.result == null) { String[] named = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, this.type); @@ -151,7 +155,7 @@ public class SpringModule implements Module { } @Override - public boolean matches(String name, Class type) { + public boolean matches(String name, Type type) { for (BindingTypeMatcher matcher : this.matchers) { if (matcher.matches(name, type)) { return true; diff --git a/src/test/java/org/springframework/guice/AbstractCompleteWiringTests.java b/src/test/java/org/springframework/guice/AbstractCompleteWiringTests.java index 09272ff..ca550bb 100644 --- a/src/test/java/org/springframework/guice/AbstractCompleteWiringTests.java +++ b/src/test/java/org/springframework/guice/AbstractCompleteWiringTests.java @@ -11,6 +11,7 @@ import org.junit.Test; import com.google.inject.Injector; import com.google.inject.Key; +import com.google.inject.TypeLiteral; import com.google.inject.name.Names; public abstract class AbstractCompleteWiringTests { @@ -74,6 +75,12 @@ public abstract class AbstractCompleteWiringTests { public void getNamedInjectedInstance() { assertNotNull(this.injector.getInstance(Thing.class).thang); } + + @Test + public void getParameterizedType() { + Parameterized instance = this.injector.getInstance(Key.get(new TypeLiteral>() {})); + assertNotNull(instance); + } public interface Service { } @@ -121,4 +128,7 @@ public abstract class AbstractCompleteWiringTests { public static class Thang { } + + public static interface Parameterized { + } } diff --git a/src/test/java/org/springframework/guice/GuiceWiringTests.java b/src/test/java/org/springframework/guice/GuiceWiringTests.java index e77ae20..f0e5b14 100644 --- a/src/test/java/org/springframework/guice/GuiceWiringTests.java +++ b/src/test/java/org/springframework/guice/GuiceWiringTests.java @@ -18,6 +18,7 @@ import javax.inject.Singleton; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; +import com.google.inject.TypeLiteral; import com.google.inject.name.Names; /** @@ -38,6 +39,7 @@ public class GuiceWiringTests extends AbstractCompleteWiringTests { bind(Service.class).to(MyService.class); bind(Baz.class).in(Singleton.class); bind(Thang.class).annotatedWith(Names.named("thing")).to(Thang.class); + bind(new TypeLiteral>(){}).toInstance(new Parameterized(){}); } } diff --git a/src/test/java/org/springframework/guice/annotation/ModuleBeanWiringTests.java b/src/test/java/org/springframework/guice/annotation/ModuleBeanWiringTests.java index 3731a52..c8c4377 100644 --- a/src/test/java/org/springframework/guice/annotation/ModuleBeanWiringTests.java +++ b/src/test/java/org/springframework/guice/annotation/ModuleBeanWiringTests.java @@ -80,6 +80,11 @@ public class ModuleBeanWiringTests extends AbstractCompleteWiringTests { public Baz baz(Service service) { return new Baz(service); } + + @Bean + public Parameterized parameterizedBean() { + return new Parameterized() {}; + } } protected static class Spam { diff --git a/src/test/java/org/springframework/guice/annotation/ModuleNamedBeanWiringTests.java b/src/test/java/org/springframework/guice/annotation/ModuleNamedBeanWiringTests.java index 3573da2..810fc24 100644 --- a/src/test/java/org/springframework/guice/annotation/ModuleNamedBeanWiringTests.java +++ b/src/test/java/org/springframework/guice/annotation/ModuleNamedBeanWiringTests.java @@ -86,6 +86,11 @@ public class ModuleNamedBeanWiringTests extends AbstractCompleteWiringTests { public Baz baz(Service service) { return new Baz(service); } + + @Bean + public Parameterized parameterizedBean() { + return new Parameterized() {}; + } } protected static class Spam { diff --git a/src/test/java/org/springframework/guice/injector/SpringWiringTests.java b/src/test/java/org/springframework/guice/injector/SpringWiringTests.java index 02ae7a6..5b01d8b 100644 --- a/src/test/java/org/springframework/guice/injector/SpringWiringTests.java +++ b/src/test/java/org/springframework/guice/injector/SpringWiringTests.java @@ -48,6 +48,10 @@ public class SpringWiringTests extends AbstractCompleteWiringTests { public Thang other() { return new Thang(); } + @Bean + public Parameterized parameterizedBean() { + return new Parameterized() {}; + } } } diff --git a/src/test/java/org/springframework/guice/module/SpringModuleWiringTests.java b/src/test/java/org/springframework/guice/module/SpringModuleWiringTests.java index 5c4364c..69e0f66 100644 --- a/src/test/java/org/springframework/guice/module/SpringModuleWiringTests.java +++ b/src/test/java/org/springframework/guice/module/SpringModuleWiringTests.java @@ -61,7 +61,10 @@ public class SpringModuleWiringTests extends AbstractCompleteWiringTests { public Thing that() { return new Thing(); } - + + @Bean + public Parameterized parameterizedBean() { + return new Parameterized(){}; + } } - }