diff --git a/src/main/java/org/springframework/guice/module/SpringModule.java b/src/main/java/org/springframework/guice/module/SpringModule.java index ee87c9d..f0b2bfe 100644 --- a/src/main/java/org/springframework/guice/module/SpringModule.java +++ b/src/main/java/org/springframework/guice/module/SpringModule.java @@ -51,7 +51,7 @@ public class SpringModule extends AbstractModule { private BindingTypeMatcher matcher = new GuiceModuleMetadata(); - private Map> bound = new HashMap>(); + private Map> bound = new HashMap>(); private ConfigurableListableBeanFactory beanFactory; @@ -140,19 +140,56 @@ public class SpringModule extends AbstractModule { } } } - - if (this.bound.get(type) == null) { + StageTypeKey stageTypeKey = new StageTypeKey(binder.currentStage(), type); + if (this.bound.get(stageTypeKey) == null) { // Only bind one provider for each type binder.withSource("spring-guice").bind(Key.get(type)) - .toProvider(typeProvider).in(Scopes.SINGLETON); - if(binder.currentStage() != Stage.TOOL) { - this.bound.put(type, typeProvider); - } + .toProvider(typeProvider); + this.bound.put(stageTypeKey, typeProvider); } // But allow binding to named beans binder.withSource("spring-guice").bind(TypeLiteral.get(type)) .annotatedWith(Names.named(name)).toProvider(namedProvider); } + + private static class StageTypeKey { + + private final Stage stage; + private final Type type; + + public StageTypeKey(Stage stage, Type type) { + this.stage = stage; + this.type = type; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((stage == null) ? 0 : stage.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + StageTypeKey other = (StageTypeKey) obj; + if (stage != other.stage) + return false; + if (type == null) { + if (other.type != null) + return false; + } else if (!type.equals(other.type)) + return false; + return true; + } + } private static class BeanFactoryProvider implements Provider { diff --git a/src/test/java/org/springframework/guice/BeanPostProcessorTest.java b/src/test/java/org/springframework/guice/BeanPostProcessorTests.java similarity index 89% rename from src/test/java/org/springframework/guice/BeanPostProcessorTest.java rename to src/test/java/org/springframework/guice/BeanPostProcessorTests.java index 0e5e9c0..b758733 100644 --- a/src/test/java/org/springframework/guice/BeanPostProcessorTest.java +++ b/src/test/java/org/springframework/guice/BeanPostProcessorTests.java @@ -10,16 +10,16 @@ import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.guice.BeanPostProcessorTest.GuiceBeanThatWantsPostProcessedBean; -import org.springframework.guice.BeanPostProcessorTest.GuiceBeanThatWantsSpringBean; -import org.springframework.guice.BeanPostProcessorTest.PostProcessedBean; -import org.springframework.guice.BeanPostProcessorTest.SpringBeanThatWantsPostProcessedBean; +import org.springframework.guice.BeanPostProcessorTests.GuiceBeanThatWantsPostProcessedBean; +import org.springframework.guice.BeanPostProcessorTests.GuiceBeanThatWantsSpringBean; +import org.springframework.guice.BeanPostProcessorTests.PostProcessedBean; +import org.springframework.guice.BeanPostProcessorTests.SpringBeanThatWantsPostProcessedBean; import org.springframework.guice.annotation.EnableGuiceModules; import com.google.inject.AbstractModule; import com.google.inject.Module; -public class BeanPostProcessorTest { +public class BeanPostProcessorTests { /** * Verify BeanPostProcessor's such as Spring Boot's diff --git a/src/test/java/org/springframework/guice/ElementVisitorTests.java b/src/test/java/org/springframework/guice/ElementVisitorTests.java new file mode 100644 index 0000000..2185f82 --- /dev/null +++ b/src/test/java/org/springframework/guice/ElementVisitorTests.java @@ -0,0 +1,118 @@ +package org.springframework.guice; + +import static org.junit.Assert.assertEquals; + +import java.util.List; + +import javax.inject.Inject; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.guice.ElementVisitorTests.DuplicateBean; +import org.springframework.guice.ElementVisitorTests.ElementVisitorTestGuiceBean; +import org.springframework.guice.ElementVisitorTests.ElementVisitorTestSpringBean; +import org.springframework.guice.annotation.EnableGuiceModules; +import org.springframework.guice.annotation.InjectorFactory; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Module; +import com.google.inject.Stage; +import com.google.inject.spi.Element; +import com.google.inject.spi.Elements; + +public class ElementVisitorTests { + + private static AnnotationConfigApplicationContext context; + + @BeforeClass + public static void init() { + context = new AnnotationConfigApplicationContext(ElementVisitorTestConfig.class); + } + + @AfterClass + public static void cleanup() { + if(context != null) { + context.close(); + } + } + + @Test + public void verifySpringModuleDoesNotBreakWhenUsingElementVisitors() { + ElementVisitorTestSpringBean testSpringBean = context.getBean(ElementVisitorTestSpringBean.class); + assertEquals("spring created", testSpringBean.toString()); + ElementVisitorTestGuiceBean testGuiceBean = context.getBean(ElementVisitorTestGuiceBean.class); + assertEquals("spring created", testGuiceBean.toString()); + } + + + public static class ElementVisitorTestSpringBean { + @Override + public String toString() { + return "default"; + } + } + + public static class ElementVisitorTestGuiceBean { + @Inject + ElementVisitorTestSpringBean springBean; + @Override + public String toString() { + return springBean.toString(); + } + } + + public static class DuplicateBean {} +} + +@EnableGuiceModules +@Configuration +class ElementVisitorTestConfig { + + @Bean + public ElementVisitorTestSpringBean testBean() { + return new ElementVisitorTestSpringBean(){ + @Override + public String toString() { + return "spring created"; + } + }; + } + + @Bean + public Module module() { + return new AbstractModule() { + @Override + protected void configure() { + binder().requireExplicitBindings(); + bind(ElementVisitorTestGuiceBean.class).asEagerSingleton(); + } + }; + } + + @Bean + public InjectorFactory injectorFactory() { + return new InjectorFactory() { + @Override + public Injector createInjector(List modules) { + List elements = Elements.getElements(Stage.TOOL, modules); + return Guice.createInjector(Stage.PRODUCTION,Elements.getModule(elements)); + } + }; + } + + @Bean + public DuplicateBean dupeBean1() { + return new DuplicateBean(); + } + + @Bean + public DuplicateBean dupeBean2() { + return new DuplicateBean(); + } +} \ No newline at end of file