Extract metadata for includes and excludes
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -47,7 +47,7 @@
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<java.version>1.7</java.version>
|
||||
<java.version>1.6</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
</properties>
|
||||
|
||||
115
src/main/java/org/springframework/guice/GuiceModuleMetadata.java
Normal file
115
src/main/java/org/springframework/guice/GuiceModuleMetadata.java
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.io.IOException;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Encapsulates some metadata about a Guice module that is to be created from the parent
|
||||
* context of a <code>@Bean</code> of this type.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class GuiceModuleMetadata {
|
||||
|
||||
private TypeFilter[] includeFilters;
|
||||
|
||||
private TypeFilter[] excludeFilters;
|
||||
|
||||
private Set<Class<?>> infrastructureTypes = new HashSet<Class<?>>();
|
||||
|
||||
{
|
||||
infrastructureTypes.add(InitializingBean.class);
|
||||
infrastructureTypes.add(DisposableBean.class);
|
||||
}
|
||||
|
||||
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
|
||||
|
||||
public GuiceModuleMetadata include(TypeFilter... filters) {
|
||||
includeFilters = filters;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GuiceModuleMetadata exclude(TypeFilter... filters) {
|
||||
excludeFilters = filters;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean matches(Class<?> type) {
|
||||
|
||||
if (infrastructureTypes.contains(type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!visible(type)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (includeFilters != null) {
|
||||
try {
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (excludeFilters != null) {
|
||||
try {
|
||||
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);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean visible(Class<?> type) {
|
||||
Class<?> cls = type;
|
||||
while (cls != null && cls != Object.class) {
|
||||
if (!Modifier.isPublic(cls.getModifiers())) {
|
||||
return false;
|
||||
}
|
||||
cls = cls.getDeclaringClass();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
package org.springframework.guice;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
@@ -30,10 +31,17 @@ import com.google.inject.Provider;
|
||||
public class SpringModule implements Module {
|
||||
|
||||
private DefaultListableBeanFactory beanFactory;
|
||||
|
||||
private GuiceModuleMetadata metadata = new GuiceModuleMetadata();
|
||||
|
||||
public SpringModule(GenericApplicationContext context) {
|
||||
this.beanFactory = (DefaultListableBeanFactory) context
|
||||
.getAutowireCapableBeanFactory();
|
||||
if (beanFactory.getBeanNamesForType(GuiceModuleMetadata.class).length>0) {
|
||||
this.metadata = beanFactory.getBean(GuiceModuleMetadata.class);
|
||||
} else if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(beanFactory, GuiceModuleMetadata.class).length>0) {
|
||||
this.metadata = beanFactory.getBean(GuiceModuleMetadata.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -45,22 +53,31 @@ public class SpringModule implements Module {
|
||||
Class<?> type = beanFactory.getType(name);
|
||||
@SuppressWarnings("unchecked")
|
||||
final Class<Object> cls = (Class<Object>) type;
|
||||
final String beanName = name;
|
||||
Provider<Object> provider = new Provider<Object>() {
|
||||
@Override
|
||||
public Object get() {
|
||||
return beanFactory.getBean(cls);
|
||||
return beanFactory.getBean(beanName, cls);
|
||||
}
|
||||
};
|
||||
if (!cls.isInterface()) {
|
||||
binder.bind(cls).toProvider(provider);
|
||||
if (!cls.isInterface() && !ClassUtils.isCglibProxyClass(cls)) {
|
||||
bindConditionally(binder, cls, provider);
|
||||
}
|
||||
for (Class<?> iface : ClassUtils.getAllInterfacesForClass(cls)) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<Object> unchecked = (Class<Object>) iface;
|
||||
binder.bind(unchecked).toProvider(provider);
|
||||
bindConditionally(binder, unchecked, provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void bindConditionally(Binder binder, Class<Object> cls,
|
||||
Provider<Object> provider) {
|
||||
if (!metadata.matches(cls)) {
|
||||
return;
|
||||
}
|
||||
binder.bind(cls).toProvider(provider);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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.cache.annotation.Cacheable;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||
import org.springframework.core.type.filter.AssignableTypeFilter;
|
||||
|
||||
import com.google.inject.ConfigurationException;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class SpringModuleMetadataTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException expected = ExpectedException.none();
|
||||
|
||||
@Test
|
||||
public void twoConfigClasses() throws Exception {
|
||||
Injector injector = createInjector(TestConfig.class, OtherConfig.class);
|
||||
expected.expect(ConfigurationException.class);
|
||||
assertNull(injector.getBinding(Service.class));
|
||||
}
|
||||
|
||||
@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.getBinding(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
|
||||
protected static class MetadataExcludesConfig {
|
||||
@Bean
|
||||
public GuiceModuleMetadata guiceModuleMetadata() {
|
||||
GuiceModuleMetadata metadata = new GuiceModuleMetadata();
|
||||
metadata.exclude(new AssignableTypeFilter(Service.class));
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class MetadataIncludesConfig {
|
||||
@Bean
|
||||
public GuiceModuleMetadata guiceModuleMetadata() {
|
||||
GuiceModuleMetadata metadata = new GuiceModuleMetadata();
|
||||
metadata.include(new AnnotationTypeFilter(Cacheable.class));
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class TestConfig {
|
||||
@Bean
|
||||
public Service service() {
|
||||
return new MyService();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class OtherConfig {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
package org.springframework.guice;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -26,6 +28,9 @@ import com.google.inject.Injector;
|
||||
*/
|
||||
public class SpringModuleWiringTests extends AbstractCompleteWiringTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException expected = ExpectedException.none();
|
||||
|
||||
@Override
|
||||
protected Injector createInjector() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
@@ -40,6 +45,7 @@ public class SpringModuleWiringTests extends AbstractCompleteWiringTests {
|
||||
public Service service() {
|
||||
return new MyService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Baz baz() {
|
||||
return new Baz(service());
|
||||
|
||||
Reference in New Issue
Block a user