Added support for automatically binding Spring beans.
git-svn-id: https://google-guice.googlecode.com/svn/trunk@273 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/spring/src/com/google/inject/spring/SpringIntegration.java b/spring/src/com/google/inject/spring/SpringIntegration.java
index f791ae8..3a67147 100644
--- a/spring/src/com/google/inject/spring/SpringIntegration.java
+++ b/spring/src/com/google/inject/spring/SpringIntegration.java
@@ -16,30 +16,73 @@
package com.google.inject.spring;
+import static com.google.inject.util.Objects.nonNull;
import com.google.inject.Provider;
import com.google.inject.Inject;
+import com.google.inject.Binder;
+import com.google.inject.name.Names;
+import com.google.inject.spi.SourceProviders;
+import com.google.inject.util.Objects;
import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.ListableBeanFactory;
/**
- * Integrates Guice with Spring. Requires a binding to
- * {@link org.springframework.beans.factory.BeanFactory}.
+ * Integrates Guice with Spring.
*
* @author crazybob@google.com (Bob Lee)
*/
public class SpringIntegration {
+ static {
+ SourceProviders.skip(SpringIntegration.class);
+ }
+
private SpringIntegration() {}
/**
* Creates a provider which looks up objects from Spring using the given name.
- * Example usage:
+ * Expects a binding to {@link
+ * org.springframework.beans.factory.BeanFactory}. Example usage:
*
* <pre>
- * bind(DataSource.class).toProvider(fromSpring(DataSource.class, "dataSource"));
+ * bind(DataSource.class)
+ * .toProvider(fromSpring(DataSource.class, "dataSource"));
* </pre>
*/
public static <T> Provider<T> fromSpring(Class<T> type, String name) {
- return new SpringProvider<T>(type, name);
+ return new InjectableSpringProvider<T>(type, name);
+ }
+
+ /**
+ * Binds all Spring beans from the given factory by name. For a Spring bean
+ * named "foo", this method creates a binding to the bean's type and
+ * {@code @Named("foo")}.
+ *
+ * @see com.google.inject.name.Named
+ * @see com.google.inject.name.Names#named(String)
+ */
+ public static void bindAll(Binder binder, ListableBeanFactory beanFactory) {
+ for (String name : beanFactory.getBeanDefinitionNames()) {
+ Class<?> type = beanFactory.getType(name);
+ bindBean(binder, beanFactory, name, type);
+ }
+ }
+
+ static <T> void bindBean(Binder binder, ListableBeanFactory beanFactory,
+ String name, Class<T> type) {
+ SpringProvider<T> provider
+ = SpringProvider.newInstance(type, name);
+ try {
+ provider.initialize(beanFactory);
+ }
+ catch (Exception e) {
+ binder.addError(e);
+ return;
+ }
+
+ binder.bind(type)
+ .annotatedWith(Names.named(name))
+ .toProvider(provider);
}
static class SpringProvider<T> implements Provider<T> {
@@ -50,11 +93,14 @@
final String name;
public SpringProvider(Class<T> type, String name) {
- this.type = type;
- this.name = name;
+ this.type = nonNull(type, "type");
+ this.name = nonNull(name, "name");
}
- @Inject
+ static <T> SpringProvider<T> newInstance(Class<T> type, String name) {
+ return new SpringProvider<T>(type, name);
+ }
+
void initialize(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
if (!beanFactory.isTypeMatch(name, type)) {
@@ -77,4 +123,17 @@
return instance;
}
}
+
+ static class InjectableSpringProvider<T> extends SpringProvider<T> {
+
+ InjectableSpringProvider(Class<T> type, String name) {
+ super(type, name);
+ }
+
+ @Inject
+ @Override
+ void initialize(BeanFactory beanFactory) {
+ super.initialize(beanFactory);
+ }
+ }
}
diff --git a/spring/test/com/google/inject/spring/SpringIntegrationTest.java b/spring/test/com/google/inject/spring/SpringIntegrationTest.java
index 048c050..c110ca4 100644
--- a/spring/test/com/google/inject/spring/SpringIntegrationTest.java
+++ b/spring/test/com/google/inject/spring/SpringIntegrationTest.java
@@ -26,6 +26,8 @@
import com.google.inject.Guice;
import com.google.inject.AbstractModule;
import com.google.inject.CreationException;
+import com.google.inject.Key;
+import com.google.inject.name.Names;
import static com.google.inject.spring.SpringIntegration.*;
/**
@@ -33,7 +35,7 @@
*/
public class SpringIntegrationTest extends TestCase {
- public void testSpringIntegration() throws CreationException {
+ public void testBindFromSpring() throws CreationException {
final DefaultListableBeanFactory beanFactory
= new DefaultListableBeanFactory();
@@ -64,6 +66,38 @@
injector.getInstance(Prototype.class));
}
+ public void testBindAll() throws CreationException {
+ final DefaultListableBeanFactory beanFactory
+ = new DefaultListableBeanFactory();
+
+ RootBeanDefinition singleton
+ = new RootBeanDefinition(Singleton.class);
+ beanFactory.registerBeanDefinition("singleton", singleton);
+
+ RootBeanDefinition prototype
+ = new RootBeanDefinition(Prototype.class, false);
+ beanFactory.registerBeanDefinition("prototype", prototype);
+
+ Injector injector = Guice.createInjector(new AbstractModule() {
+ protected void configure() {
+ SpringIntegration.bindAll(binder(), beanFactory);
+ }
+ });
+
+ Key<Singleton> singletonKey
+ = Key.get(Singleton.class, Names.named("singleton"));
+ Key<Prototype> prototypeKey
+ = Key.get(Prototype.class, Names.named("prototype"));
+
+ assertNotNull(injector.getInstance(singletonKey));
+ assertSame(injector.getInstance(singletonKey),
+ injector.getInstance(singletonKey));
+
+ assertNotNull(injector.getInstance(prototypeKey));
+ assertNotSame(injector.getInstance(prototypeKey),
+ injector.getInstance(prototypeKey));
+ }
+
static class Singleton {}
static class Prototype {}
}