Add @GuiceModules with includes and excludes
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.guice;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.AspectJTypeFilter;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
import org.springframework.core.type.filter.RegexPatternTypeFilter;
|
||||
import org.springframework.core.type.filter.TypeFilter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class GuiceModuleMetadataRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
ResourceLoaderAware {
|
||||
|
||||
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata annotation,
|
||||
BeanDefinitionRegistry registry) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(GuiceModuleMetadataFactory.class);
|
||||
builder.addPropertyValue("includeFilters",
|
||||
parseFilters(annotation, "includeFilters"));
|
||||
builder.addPropertyValue("excludeFilters",
|
||||
parseFilters(annotation, "excludeFilters"));
|
||||
registry.registerBeanDefinition(GuiceModules.class.getName(),
|
||||
builder.getBeanDefinition());
|
||||
}
|
||||
|
||||
public static class GuiceModuleMetadataFactory implements
|
||||
FactoryBean<GuiceModuleMetadata> {
|
||||
|
||||
private Collection<? extends TypeFilter> includeFilters;
|
||||
|
||||
private Collection<? extends TypeFilter> excludeFilters;
|
||||
|
||||
public void setIncludeFilters(Collection<? extends TypeFilter> includeFilters) {
|
||||
this.includeFilters = includeFilters;
|
||||
}
|
||||
|
||||
public void setExcludeFilters(Collection<? extends TypeFilter> excludeFilters) {
|
||||
this.excludeFilters = excludeFilters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuiceModuleMetadata getObject() throws Exception {
|
||||
return new GuiceModuleMetadata()
|
||||
.include(
|
||||
includeFilters.toArray(new TypeFilter[includeFilters.size()]))
|
||||
.exclude(
|
||||
excludeFilters.toArray(new TypeFilter[excludeFilters.size()]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return GuiceModuleMetadata.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Set<TypeFilter> parseFilters(AnnotationMetadata annotation,
|
||||
String attributeName) {
|
||||
|
||||
Set<TypeFilter> result = new HashSet<TypeFilter>();
|
||||
AnnotationAttributes attributes = new AnnotationAttributes(
|
||||
annotation.getAnnotationAttributes(GuiceModules.class.getName()));
|
||||
AnnotationAttributes[] filters = attributes.getAnnotationArray(attributeName);
|
||||
|
||||
for (AnnotationAttributes filter : filters) {
|
||||
result.addAll(typeFiltersFor(filter));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
|
||||
|
||||
List<TypeFilter> typeFilters = new ArrayList<TypeFilter>();
|
||||
FilterType filterType = filterAttributes.getEnum("type");
|
||||
|
||||
for (Class<?> filterClass : filterAttributes.getClassArray("value")) {
|
||||
switch (filterType) {
|
||||
case ANNOTATION:
|
||||
Assert.isAssignable(Annotation.class, filterClass,
|
||||
"An error occured when processing a @ComponentScan "
|
||||
+ "ANNOTATION type filter: ");
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<Annotation> annoClass = (Class<Annotation>) filterClass;
|
||||
typeFilters.add(new AnnotationTypeFilter(annoClass));
|
||||
break;
|
||||
case ASSIGNABLE_TYPE:
|
||||
typeFilters.add(new AssignableTypeFilter(filterClass));
|
||||
break;
|
||||
case CUSTOM:
|
||||
Assert.isAssignable(TypeFilter.class, filterClass,
|
||||
"An error occured when processing a @ComponentScan "
|
||||
+ "CUSTOM type filter: ");
|
||||
typeFilters
|
||||
.add(BeanUtils.instantiateClass(filterClass, TypeFilter.class));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown filter type " + filterType);
|
||||
}
|
||||
}
|
||||
|
||||
for (String expression : getPatterns(filterAttributes)) {
|
||||
|
||||
String rawName = filterType.toString();
|
||||
|
||||
if ("REGEX".equals(rawName)) {
|
||||
typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(expression)));
|
||||
} else if ("ASPECTJ".equals(rawName)) {
|
||||
typeFilters.add(new AspectJTypeFilter(expression, this.resourceLoader
|
||||
.getClassLoader()));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unknown filter type " + filterType);
|
||||
}
|
||||
}
|
||||
|
||||
return typeFilters;
|
||||
}
|
||||
|
||||
private String[] getPatterns(AnnotationAttributes filterAttributes) {
|
||||
|
||||
try {
|
||||
return filterAttributes.getStringArray("pattern");
|
||||
} catch (IllegalArgumentException o_O) {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
45
src/main/java/org/springframework/guice/GuiceModules.java
Normal file
45
src/main/java/org/springframework/guice/GuiceModules.java
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.guice;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Import(GuiceModuleMetadataRegistrar.class)
|
||||
public @interface GuiceModules {
|
||||
|
||||
/**
|
||||
* Specifies which types are eligible for inclusion in Guice module
|
||||
*/
|
||||
Filter[] includeFilters() default {};
|
||||
|
||||
/**
|
||||
* Specifies which types are not eligible for inclusion in Guice module.
|
||||
*/
|
||||
Filter[] excludeFilters() default {};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.guice;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.FilterType;
|
||||
|
||||
import com.google.inject.ConfigurationException;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class GuiceModulesTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException expected = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void includes() throws Exception {
|
||||
Injector injector = createInjector(TestConfig.class, MetadataIncludesConfig.class);
|
||||
expected.expect(ConfigurationException.class);
|
||||
assertNull(injector.getBinding(Service.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void excludes() throws Exception {
|
||||
Injector injector = createInjector(TestConfig.class, MetadataExcludesConfig.class);
|
||||
expected.expect(ConfigurationException.class);
|
||||
assertNull(injector.getInstance(Service.class));
|
||||
}
|
||||
|
||||
private Injector createInjector(Class<?>... config) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(config);
|
||||
context.refresh();
|
||||
Injector injector = Guice.createInjector(new SpringModule(context));
|
||||
return injector;
|
||||
}
|
||||
|
||||
interface Service {
|
||||
}
|
||||
|
||||
protected static class MyService implements Service {
|
||||
}
|
||||
|
||||
public static class Foo {
|
||||
|
||||
@Inject
|
||||
public Foo(Service service) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@GuiceModules(excludeFilters=@Filter(type=FilterType.REGEX, pattern=".*"))
|
||||
protected static class MetadataExcludesConfig {
|
||||
}
|
||||
|
||||
// TODO: allow include Service.class as well
|
||||
@Configuration
|
||||
@GuiceModules(includeFilters=@Filter(type=FilterType.ASSIGNABLE_TYPE, value=MyService.class))
|
||||
protected static class MetadataIncludesConfig {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class TestConfig {
|
||||
@Bean
|
||||
public Service service() {
|
||||
return new MyService();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user