make bean names unique when considering binding annotations
translate binding annotations into Spring @Qualifiers
This commit is contained in:
committed by
Taylor Wicksell
parent
0153079327
commit
2207c4f1d9
@@ -37,9 +37,11 @@ import com.google.inject.spi.PrivateElements;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
@@ -66,7 +68,6 @@ class ModuleRegistryConfiguration implements BeanDefinitionRegistryPostProcessor
|
||||
private static final String SPRING_GUICE_DEDUPE_BINDINGS_PROPERTY_NAME = "spring.guice.dedup";
|
||||
private ApplicationContext applicationContext;
|
||||
private List<Module> modules;
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
private AtomicBoolean injectorCreated = new AtomicBoolean(false);
|
||||
|
||||
private void createInjector(List<Module> modules,
|
||||
@@ -122,19 +123,33 @@ class ModuleRegistryConfiguration implements BeanDefinitionRegistryPostProcessor
|
||||
bean.setResourceDescription(SpringModule.SPRING_GUICE_SOURCE);
|
||||
}
|
||||
bean.setAttribute(SpringModule.SPRING_GUICE_SOURCE, true);
|
||||
if (key.getAnnotation() != null) {
|
||||
bean.addQualifier(new AutowireCandidateQualifier(Qualifier.class,
|
||||
getValueAttributeForNamed(key.getAnnotation())));
|
||||
}
|
||||
registry.registerBeanDefinition(extractName(key), bean);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String extractName(Key<?> key) {
|
||||
final Annotation annotation = key.getAnnotation();
|
||||
final String className = key.getTypeLiteral().getRawType().getSimpleName();
|
||||
String valueAttribute = getValueAttributeForNamed(key.getAnnotation());
|
||||
if (valueAttribute != null) {
|
||||
return valueAttribute + "_" + className;
|
||||
} else {
|
||||
return className;
|
||||
}
|
||||
}
|
||||
|
||||
private String getValueAttributeForNamed(Annotation annotation) {
|
||||
if (annotation instanceof Named) {
|
||||
return ((Named) annotation).value();
|
||||
} else if (annotation instanceof javax.inject.Named) {
|
||||
return ((javax.inject.Named) annotation).value();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return key.getTypeLiteral().getRawType().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -235,7 +250,6 @@ class ModuleRegistryConfiguration implements BeanDefinitionRegistryPostProcessor
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
beanFactory.registerSingleton("guiceInjectorInitializer", new GuiceInjectorInitializingBeanPostProcessor(){
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
|
||||
@@ -18,6 +18,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -128,8 +129,12 @@ public class SpringInjector implements Injector {
|
||||
@SuppressWarnings("unchecked")
|
||||
final Class<T> cls = (Class<T>) type;
|
||||
return new Provider<T>() {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T get() {
|
||||
if(key.getAnnotation() != null) {
|
||||
return (T) BeanFactoryAnnotationUtils.qualifiedBeanOfType(SpringInjector.this.beanFactory, type, name);
|
||||
}
|
||||
return SpringInjector.this.beanFactory.getBean(cls);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -20,6 +20,8 @@ import org.springframework.guice.BindingAnnotationTests.SomeDependencyWithNamedA
|
||||
import org.springframework.guice.BindingAnnotationTests.SomeDependencyWithQualifierOnProvider;
|
||||
import org.springframework.guice.BindingAnnotationTests.SomeDependencyWithQualifierOnProviderWhichImplementsSomeInterface;
|
||||
import org.springframework.guice.BindingAnnotationTests.SomeInterface;
|
||||
import org.springframework.guice.BindingAnnotationTests.SomeNamedDepWithType1;
|
||||
import org.springframework.guice.BindingAnnotationTests.SomeNamedDepWithType2;
|
||||
import org.springframework.guice.annotation.EnableGuiceModules;
|
||||
|
||||
import com.google.inject.BindingAnnotation;
|
||||
@@ -61,6 +63,12 @@ public class BindingAnnotationTests {
|
||||
SomeInterface someInterface = injector.getInstance(Key.get(SomeInterface.class, SomeQualifierAnnotation.class));
|
||||
assertNotNull(someInterface);
|
||||
|
||||
//Check different types with same @Named
|
||||
assertNotNull(injector.getInstance(SomeNamedDepWithType1.class));
|
||||
assertNotNull(injector.getInstance(SomeNamedDepWithType2.class));
|
||||
|
||||
assertNotNull(injector.getInstance(Key.get(SomeNamedDepWithType1.class, Names.named("sameNameDifferentType"))));
|
||||
assertNotNull(injector.getInstance(Key.get(SomeNamedDepWithType2.class, Names.named("sameNameDifferentType"))));
|
||||
context.close();
|
||||
}
|
||||
|
||||
@@ -71,6 +79,8 @@ public class BindingAnnotationTests {
|
||||
public static class SomeDependencyWithGuiceNamedAnnotationOnProvider {}
|
||||
public static interface SomeInterface{}
|
||||
public static class SomeDependencyWithQualifierOnProviderWhichImplementsSomeInterface implements SomeInterface {}
|
||||
public static class SomeNamedDepWithType1 {}
|
||||
public static class SomeNamedDepWithType2 {}
|
||||
}
|
||||
|
||||
@Qualifier
|
||||
@@ -129,4 +139,16 @@ class BindingAnnotationTestsConfig {
|
||||
public SomeInterface someInterface() {
|
||||
return new SomeDependencyWithQualifierOnProviderWhichImplementsSomeInterface();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Named("sameNameDifferentType")
|
||||
public SomeNamedDepWithType1 someNamedDepWithType1() {
|
||||
return new SomeNamedDepWithType1();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Named("sameNameDifferentType")
|
||||
public SomeNamedDepWithType2 someNamedDepWithType2() {
|
||||
return new SomeNamedDepWithType2();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package org.springframework.guice;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.guice.DuplicateNamesDifferentTypesTests.SomeJavaxNamedDepWithType1;
|
||||
import org.springframework.guice.DuplicateNamesDifferentTypesTests.SomeJavaxNamedDepWithType2;
|
||||
import org.springframework.guice.DuplicateNamesDifferentTypesTests.SomeNamedDepWithType1;
|
||||
import org.springframework.guice.DuplicateNamesDifferentTypesTests.SomeNamedDepWithType2;
|
||||
import org.springframework.guice.annotation.EnableGuiceModules;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.name.Named;
|
||||
import com.google.inject.name.Names;
|
||||
|
||||
public class DuplicateNamesDifferentTypesTests {
|
||||
|
||||
@Test
|
||||
public void verifyNoDuplicateBindingErrorWhenDedupeEnabled() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
DuplicateNamesDifferentTypesTestsConfig.class);
|
||||
|
||||
//Check Guice @Named
|
||||
assertNotNull(context.getBean(SomeNamedDepWithType1.class));
|
||||
assertNotNull(context.getBean(SomeNamedDepWithType2.class));
|
||||
assertNotNull(BeanFactoryAnnotationUtils.qualifiedBeanOfType(context.getBeanFactory(), SomeNamedDepWithType1.class, "sameNameDifferentType"));
|
||||
|
||||
//Check javax @Named
|
||||
assertNotNull(context.getBean(SomeJavaxNamedDepWithType1.class));
|
||||
assertNotNull(context.getBean(SomeJavaxNamedDepWithType2.class));
|
||||
assertNotNull(BeanFactoryAnnotationUtils.qualifiedBeanOfType(context.getBeanFactory(), SomeJavaxNamedDepWithType1.class, "sameJavaxName"));
|
||||
context.getBeansOfType(SomeJavaxNamedDepWithType1.class);
|
||||
|
||||
context.close();
|
||||
}
|
||||
|
||||
public static class SomeNamedDepWithType1 {}
|
||||
public static class SomeNamedDepWithType2 {}
|
||||
public static class SomeJavaxNamedDepWithType1 {}
|
||||
public static class SomeJavaxNamedDepWithType2 {}
|
||||
|
||||
public static class SomeClassWithDeps{
|
||||
@Autowired
|
||||
@Qualifier("sameJavaxName2")
|
||||
SomeJavaxNamedDepWithType1 qualified;
|
||||
|
||||
@Autowired
|
||||
@Named("sameJavaxName2")
|
||||
SomeJavaxNamedDepWithType1 named;
|
||||
|
||||
@Autowired
|
||||
@javax.inject.Named("sameJavaxName2")
|
||||
SomeJavaxNamedDepWithType1 javaxNamed;
|
||||
}
|
||||
}
|
||||
|
||||
@EnableGuiceModules
|
||||
@Configuration
|
||||
class DuplicateNamesDifferentTypesTestsConfig {
|
||||
|
||||
@Bean
|
||||
public Module module() {
|
||||
return new AbstractModule() {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(SomeNamedDepWithType1.class).annotatedWith(Names.named("sameNameDifferentType"))
|
||||
.to(SomeNamedDepWithType1.class);
|
||||
bind(SomeNamedDepWithType2.class).annotatedWith(Names.named("sameNameDifferentType"))
|
||||
.to(SomeNamedDepWithType2.class);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named("sameJavaxName")
|
||||
public SomeJavaxNamedDepWithType1 someJavaxNamedDepWithType1() {
|
||||
return new SomeJavaxNamedDepWithType1();
|
||||
}
|
||||
|
||||
|
||||
@Provides
|
||||
@Named("sameJavaxName")
|
||||
public SomeJavaxNamedDepWithType2 someJavaxNamedDepWithType2() {
|
||||
return new SomeJavaxNamedDepWithType2();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -45,7 +46,8 @@ public class PrivateModuleTests {
|
||||
assertNotNull(injectorProvidedPrivateBinding);
|
||||
SomeInterface springProvidedPrivateBinding = context.getBean(SomeInterface.class);
|
||||
assertNotNull(springProvidedPrivateBinding);
|
||||
SomeInterface namedPrivateBinding = context.getBean("exposed",SomeInterface.class);
|
||||
SomeInterface namedPrivateBinding = BeanFactoryAnnotationUtils.qualifiedBeanOfType(context.getBeanFactory(),
|
||||
SomeInterface.class, "exposed");
|
||||
assertNotNull(namedPrivateBinding);
|
||||
assertEquals(injectorProvidedPrivateBinding, springProvidedPrivateBinding);
|
||||
assertEquals(injectorProvidedPrivateBinding, namedPrivateBinding);
|
||||
@@ -64,6 +66,11 @@ public class PrivateModuleTests {
|
||||
public void verifyPrivateModulesPrivateBindingsAreNotExposedViaSpring() {
|
||||
context.getBean("notexposed",SomeInterface.class);
|
||||
}
|
||||
|
||||
@Test(expected = NoSuchBeanDefinitionException.class)
|
||||
public void verifyPrivateModulesPrivateBindingsAreNotExposedViaSpringWithQualifier() {
|
||||
BeanFactoryAnnotationUtils.qualifiedBeanOfType(context.getBeanFactory(), SomeInterface.class, "notexposed");
|
||||
}
|
||||
|
||||
public static interface SomeInterface {}
|
||||
public static class SomePrivateBinding implements SomeInterface {}
|
||||
|
||||
Reference in New Issue
Block a user