Add bean name filters to GuiceModule
This commit is contained in:
@@ -22,6 +22,6 @@ package org.springframework.guice;
|
||||
*/
|
||||
public interface BindingTypeMatcher {
|
||||
|
||||
boolean matches(Class<?> type);
|
||||
boolean matches(String name, Class<?> type);
|
||||
|
||||
}
|
||||
|
||||
@@ -52,4 +52,24 @@ public @interface GuiceModule {
|
||||
*/
|
||||
Filter[] excludeFilters() default {};
|
||||
|
||||
/**
|
||||
* Specifies which names (by regex) are eligible for inclusion in Guice module
|
||||
*/
|
||||
String[] includePatterns() default {};
|
||||
|
||||
/**
|
||||
* Specifies which bean names (by regex) are not eligible for inclusion in Guice module.
|
||||
*/
|
||||
String[] excludePatterns() default {};
|
||||
|
||||
/**
|
||||
* Specifies which names (by simple wildcard match) are eligible for inclusion in Guice module
|
||||
*/
|
||||
String[] includeNames() default {};
|
||||
|
||||
/**
|
||||
* Specifies which bean names (by simple wildcard match) are not eligible for inclusion in Guice module.
|
||||
*/
|
||||
String[] excludeNames() default {};
|
||||
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
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;
|
||||
@@ -27,12 +28,12 @@ import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.util.PatternMatchUtils;
|
||||
|
||||
/**
|
||||
* Encapsulates some metadata about a Guice module that is to be created from the parent
|
||||
* context of a <code>@Bean</code> of this type. Can be used directly as a
|
||||
* <code>@Bean</code>, but it is easier to just add <code>@</code>{@link GuiceModule} to
|
||||
* your <code>@Configuration</code>.
|
||||
* Encapsulates some metadata about a Guice module that is to be created from the parent context of a <code>@Bean</code>
|
||||
* of this type. Can be used directly as a <code>@Bean</code>, but it is easier to just add <code>@</code>
|
||||
* {@link GuiceModule} to your <code>@Configuration</code>.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
@@ -43,6 +44,14 @@ public class GuiceModuleMetadata implements BindingTypeMatcher {
|
||||
|
||||
private TypeFilter[] excludeFilters;
|
||||
|
||||
private Pattern[] includePatterns;
|
||||
|
||||
private Pattern[] excludePatterns;
|
||||
|
||||
private String[] includeNames;
|
||||
|
||||
private String[] excludeNames;
|
||||
|
||||
private Set<Class<?>> infrastructureTypes = new HashSet<Class<?>>();
|
||||
|
||||
{
|
||||
@@ -52,6 +61,26 @@ public class GuiceModuleMetadata implements BindingTypeMatcher {
|
||||
|
||||
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
|
||||
|
||||
public GuiceModuleMetadata include(String... filters) {
|
||||
includeNames = filters;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GuiceModuleMetadata exclude(String... filters) {
|
||||
excludeNames = filters;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GuiceModuleMetadata include(Pattern... filters) {
|
||||
includePatterns = filters;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GuiceModuleMetadata exclude(Pattern... filters) {
|
||||
excludePatterns = filters;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GuiceModuleMetadata include(TypeFilter... filters) {
|
||||
includeFilters = filters;
|
||||
return this;
|
||||
@@ -63,8 +92,42 @@ public class GuiceModuleMetadata implements BindingTypeMatcher {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Class<?> type) {
|
||||
public boolean matches(String name, Class<?> type) {
|
||||
if (!matches(name) || !matches(type)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean matches(String name) {
|
||||
if (includePatterns != null) {
|
||||
for (Pattern filter : includePatterns) {
|
||||
if (!filter.matcher(name).matches()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (excludePatterns != null) {
|
||||
for (Pattern filter : excludePatterns) {
|
||||
if (filter.matcher(name).matches()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (includeNames != null && includeNames.length>0) {
|
||||
if (!PatternMatchUtils.simpleMatch(includeNames, name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (excludeNames != null && excludeNames.length>0) {
|
||||
if (PatternMatchUtils.simpleMatch(excludeNames, name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean matches(Class<?> type) {
|
||||
if (infrastructureTypes.contains(type)) {
|
||||
return false;
|
||||
}
|
||||
@@ -75,30 +138,28 @@ public class GuiceModuleMetadata implements BindingTypeMatcher {
|
||||
|
||||
if (includeFilters != null) {
|
||||
try {
|
||||
MetadataReader reader = metadataReaderFactory.getMetadataReader(type
|
||||
.getName());
|
||||
MetadataReader reader = metadataReaderFactory.getMetadataReader(type.getName());
|
||||
for (TypeFilter filter : includeFilters) {
|
||||
if (!filter.match(reader, metadataReaderFactory)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Cannot read metadata for class " + type,
|
||||
e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException("Cannot read metadata for class " + type, e);
|
||||
}
|
||||
}
|
||||
if (excludeFilters != null) {
|
||||
try {
|
||||
MetadataReader reader = metadataReaderFactory.getMetadataReader(type
|
||||
.getName());
|
||||
MetadataReader reader = metadataReaderFactory.getMetadataReader(type.getName());
|
||||
for (TypeFilter filter : excludeFilters) {
|
||||
if (filter.match(reader, metadataReaderFactory)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Cannot read metadata for class " + type,
|
||||
e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException("Cannot read metadata for class " + type, e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -107,8 +168,7 @@ public class GuiceModuleMetadata implements BindingTypeMatcher {
|
||||
private boolean visible(Class<?> type) {
|
||||
Class<?> cls = type;
|
||||
while (cls != null && cls != Object.class) {
|
||||
if (!Modifier.isInterface(cls.getModifiers())
|
||||
&& !Modifier.isPublic(cls.getModifiers())
|
||||
if (!Modifier.isInterface(cls.getModifiers()) && !Modifier.isPublic(cls.getModifiers())
|
||||
&& !Modifier.isProtected(cls.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,14 @@ public class GuiceModuleRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
parseFilters(annotation, "includeFilters"));
|
||||
builder.addPropertyValue("excludeFilters",
|
||||
parseFilters(annotation, "excludeFilters"));
|
||||
builder.addPropertyValue("includePatterns",
|
||||
parsePatterns(annotation, "includePatterns"));
|
||||
builder.addPropertyValue("excludePatterns",
|
||||
parsePatterns(annotation, "excludePatterns"));
|
||||
builder.addPropertyValue("includeNames",
|
||||
parseNames(annotation, "includeNames"));
|
||||
builder.addPropertyValue("excludeNames",
|
||||
parseNames(annotation, "excludeNames"));
|
||||
AbstractBeanDefinition definition = builder.getBeanDefinition();
|
||||
String name = new DefaultBeanNameGenerator().generateBeanName(definition,
|
||||
registry);
|
||||
@@ -80,6 +88,14 @@ public class GuiceModuleRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
|
||||
private Collection<? extends TypeFilter> excludeFilters;
|
||||
|
||||
private Collection<Pattern> includePatterns;
|
||||
|
||||
private Collection<Pattern> excludePatterns;
|
||||
|
||||
private Collection<String> includeNames;
|
||||
|
||||
private Collection<String> excludeNames;
|
||||
|
||||
public void setIncludeFilters(Collection<? extends TypeFilter> includeFilters) {
|
||||
this.includeFilters = includeFilters;
|
||||
}
|
||||
@@ -88,13 +104,37 @@ public class GuiceModuleRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
this.excludeFilters = excludeFilters;
|
||||
}
|
||||
|
||||
public void setIncludePatterns(Collection<Pattern> includePatterns) {
|
||||
this.includePatterns = includePatterns;
|
||||
}
|
||||
|
||||
public void setExcludePatterns(Collection<Pattern> excludePatterns) {
|
||||
this.excludePatterns = excludePatterns;
|
||||
}
|
||||
|
||||
public void setIncludeNames(Collection<String> includeNames) {
|
||||
this.includeNames = includeNames;
|
||||
}
|
||||
|
||||
public void setExcludeNames(Collection<String> excludeNames) {
|
||||
this.excludeNames = excludeNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuiceModuleMetadata getObject() throws Exception {
|
||||
return new GuiceModuleMetadata()
|
||||
.include(
|
||||
includeFilters.toArray(new TypeFilter[includeFilters.size()]))
|
||||
.exclude(
|
||||
excludeFilters.toArray(new TypeFilter[excludeFilters.size()]));
|
||||
excludeFilters.toArray(new TypeFilter[excludeFilters.size()]))
|
||||
.include(
|
||||
includePatterns.toArray(new Pattern[includePatterns.size()]))
|
||||
.exclude(
|
||||
excludePatterns.toArray(new Pattern[excludePatterns.size()]))
|
||||
.include(
|
||||
includeNames.toArray(new String[includeNames.size()]))
|
||||
.exclude(
|
||||
excludeNames.toArray(new Pattern[excludeNames.size()]));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,6 +149,32 @@ public class GuiceModuleRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
|
||||
}
|
||||
|
||||
private Set<Pattern> parsePatterns(AnnotationMetadata annotation, String attributeName) {
|
||||
Set<Pattern> result = new HashSet<Pattern>();
|
||||
AnnotationAttributes attributes = new AnnotationAttributes(
|
||||
annotation.getAnnotationAttributes(GuiceModule.class.getName()));
|
||||
String[] filters = attributes.getStringArray(attributeName);
|
||||
|
||||
for (String filter : filters) {
|
||||
result.add(Pattern.compile(filter));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Set<String> parseNames(AnnotationMetadata annotation, String attributeName) {
|
||||
Set<String> result = new HashSet<String>();
|
||||
AnnotationAttributes attributes = new AnnotationAttributes(
|
||||
annotation.getAnnotationAttributes(GuiceModule.class.getName()));
|
||||
String[] filters = attributes.getStringArray(attributeName);
|
||||
|
||||
for (String filter : filters) {
|
||||
result.add(filter);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Set<TypeFilter> parseFilters(AnnotationMetadata annotation,
|
||||
String attributeName) {
|
||||
|
||||
|
||||
@@ -63,23 +63,23 @@ public class SpringModule implements Module {
|
||||
final String beanName = name;
|
||||
Provider<Object> provider = new BeanFactoryProvider(beanFactory, beanName, type);
|
||||
if (!cls.isInterface() && !ClassUtils.isCglibProxyClass(cls)) {
|
||||
bindConditionally(binder, cls, provider);
|
||||
bindConditionally(binder, name, cls, provider);
|
||||
}
|
||||
for (Class<?> iface : ClassUtils.getAllInterfacesForClass(cls)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<Object> unchecked = (Class<Object>) iface;
|
||||
bindConditionally(binder, unchecked, provider);
|
||||
bindConditionally(binder, name, unchecked, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void bindConditionally(Binder binder, Class<Object> type, Provider<Object> provider) {
|
||||
private void bindConditionally(Binder binder, String name, Class<Object> type, Provider<Object> provider) {
|
||||
if (bound.get(type) != null) {
|
||||
// Only bind one provider for each type
|
||||
return; // TODO: named beans
|
||||
}
|
||||
if (!matcher.matches(type)) {
|
||||
if (!matcher.matches(name, type)) {
|
||||
return;
|
||||
}
|
||||
if (type.getName().startsWith("com.google.inject")) {
|
||||
@@ -136,9 +136,9 @@ public class SpringModule implements Module {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Class<?> type) {
|
||||
public boolean matches(String name, Class<?> type) {
|
||||
for (BindingTypeMatcher matcher : matchers) {
|
||||
if (matcher.matches(type)) {
|
||||
if (matcher.matches(name, type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,18 @@ public class GuiceModuleAnnotationTests {
|
||||
assertNotNull(injector.getBinding(Service.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void includesNames() throws Exception {
|
||||
Injector injector = createInjector(TestConfig.class, MetadataIncludeNamesConfig.class);
|
||||
assertNotNull(injector.getBinding(Service.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void includesPatterns() throws Exception {
|
||||
Injector injector = createInjector(TestConfig.class, MetadataIncludePatternsConfig.class);
|
||||
assertNotNull(injector.getBinding(Service.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void excludes() throws Exception {
|
||||
Injector injector = createInjector(TestConfig.class, MetadataExcludesConfig.class);
|
||||
@@ -85,11 +97,26 @@ public class GuiceModuleAnnotationTests {
|
||||
protected static class MetadataExcludesConfig {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@GuiceModule(excludePatterns=".*")
|
||||
protected static class MetadataExcludesNameConfig {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@GuiceModule(includeFilters=@Filter(type=FilterType.ASSIGNABLE_TYPE, value=Service.class))
|
||||
protected static class MetadataIncludesConfig {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@GuiceModule(includeNames="*service") // Bean name filter
|
||||
protected static class MetadataIncludeNamesConfig {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@GuiceModule(includePatterns=".*service") // Bean name filter
|
||||
protected static class MetadataIncludePatternsConfig {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@GuiceModule(includeFilters=@Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class))
|
||||
protected static class MetadataMoreIncludesConfig {
|
||||
|
||||
Reference in New Issue
Block a user