support multiple stages, as can occur when using ElementVisitors

This commit is contained in:
Taylor Wicksell
2018-02-26 15:15:55 -06:00
committed by Dave Syer
parent 1af4fccde2
commit aae2e1fc47
3 changed files with 167 additions and 12 deletions

View File

@@ -51,7 +51,7 @@ public class SpringModule extends AbstractModule {
private BindingTypeMatcher matcher = new GuiceModuleMetadata();
private Map<Type, Provider<?>> bound = new HashMap<Type, Provider<?>>();
private Map<StageTypeKey, Provider<?>> bound = new HashMap<StageTypeKey, Provider<?>>();
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<T> implements Provider<T> {

View File

@@ -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

View File

@@ -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<Module> modules) {
List<Element> 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();
}
}