diff --git a/src/main/java/org/springframework/guice/annotation/ModuleRegistryConfiguration.java b/src/main/java/org/springframework/guice/annotation/ModuleRegistryConfiguration.java index 78c9928..406d256 100644 --- a/src/main/java/org/springframework/guice/annotation/ModuleRegistryConfiguration.java +++ b/src/main/java/org/springframework/guice/annotation/ModuleRegistryConfiguration.java @@ -70,9 +70,12 @@ class ModuleRegistryConfiguration implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware { private static final String SPRING_GUICE_DEDUPE_BINDINGS_PROPERTY_NAME = "spring.guice.dedup"; + private static final String SPRING_GUICE_AUTOWIRE_JIT_PROPERTY_NAME = "spring.guice.autowireJIT"; + private ApplicationContext applicationContext; private List modules; private AtomicBoolean injectorCreated = new AtomicBoolean(false); + private boolean enableJustInTimeBinding = true; private void createInjector(List modules, ConfigurableListableBeanFactory beanFactory) { @@ -178,7 +181,7 @@ class ModuleRegistryConfiguration throws BeansException { modules = new ArrayList(((ConfigurableListableBeanFactory) registry) .getBeansOfType(Module.class).values()); - modules.add(new SpringModule((ConfigurableListableBeanFactory) registry)); + modules.add(new SpringModule((ConfigurableListableBeanFactory) registry, enableJustInTimeBinding)); Map, Binding> bindings = new HashMap, Binding>(); List elements = Elements.getElements(Stage.TOOL, modules); if (applicationContext.getEnvironment().getProperty( @@ -303,6 +306,8 @@ class ModuleRegistryConfiguration public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; + this.enableJustInTimeBinding = applicationContext.getEnvironment() + .getProperty(SPRING_GUICE_AUTOWIRE_JIT_PROPERTY_NAME, Boolean.class, true); } private static class GuiceInjectorInitializingBeanPostProcessor diff --git a/src/main/java/org/springframework/guice/module/GuiceAutowireCandidateResolver.java b/src/main/java/org/springframework/guice/module/GuiceAutowireCandidateResolver.java index e8e7361..6e7b0b7 100644 --- a/src/main/java/org/springframework/guice/module/GuiceAutowireCandidateResolver.java +++ b/src/main/java/org/springframework/guice/module/GuiceAutowireCandidateResolver.java @@ -67,6 +67,10 @@ class GuiceAutowireCandidateResolver extends ContextAnnotationAutowireCandidateR try { beanFactory.doResolveDependency(descriptor, beanName, null, null); } catch (NoSuchBeanDefinitionException e) { + if (e.getResolvableType() != null) { + logger.info(String.format("Use just in time binding for %s in bean: %s", + e.getResolvableType().getType().getTypeName(), beanName)); + } return true; } return super.isLazy(descriptor); diff --git a/src/main/java/org/springframework/guice/module/SpringModule.java b/src/main/java/org/springframework/guice/module/SpringModule.java index b4e0f56..830dbdd 100644 --- a/src/main/java/org/springframework/guice/module/SpringModule.java +++ b/src/main/java/org/springframework/guice/module/SpringModule.java @@ -73,12 +73,23 @@ public class SpringModule extends AbstractModule { private Provider beanFactoryProvider; + private boolean enableJustInTimeBinding = true; + public SpringModule(ApplicationContext context) { - this((ConfigurableListableBeanFactory) context.getAutowireCapableBeanFactory()); + this(context, true); + } + + public SpringModule(ApplicationContext context, boolean enableJustInTimeBinding) { + this((ConfigurableListableBeanFactory) context.getAutowireCapableBeanFactory(), enableJustInTimeBinding); } public SpringModule(ConfigurableListableBeanFactory beanFactory) { + this(beanFactory, true); + } + + public SpringModule(ConfigurableListableBeanFactory beanFactory, boolean enableJustInTimeBinding) { this.beanFactory = beanFactory; + this.enableJustInTimeBinding = enableJustInTimeBinding; } public SpringModule(Provider beanFactoryProvider) { @@ -95,10 +106,12 @@ public class SpringModule extends AbstractModule { beanFactory.getBeansOfType(ProvisionListener.class).values() .toArray(new ProvisionListener[0])); } - if (beanFactory instanceof DefaultListableBeanFactory) { - ((DefaultListableBeanFactory) beanFactory) - .setAutowireCandidateResolver(new GuiceAutowireCandidateResolver( - binder().getProvider(Injector.class))); + if (enableJustInTimeBinding) { + if (beanFactory instanceof DefaultListableBeanFactory) { + ((DefaultListableBeanFactory) beanFactory) + .setAutowireCandidateResolver(new GuiceAutowireCandidateResolver( + binder().getProvider(Injector.class))); + } } if (beanFactory.getBeanNamesForType(GuiceModuleMetadata.class).length > 0) { this.matcher = new CompositeTypeMatcher( diff --git a/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 35bd2ed..ca23fcd 100644 --- a/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,6 +1,16 @@ -{"properties": [{ - "name": "spring.guice.dedup", - "type": "java.lang.Boolean", - "description": "When using `@EnableGuiceModules`, if a Spring Bean and a Guice Binding both exist for the same type and Qualifier, the Spring Bean will be kept and the Guice Binding discarded.", - "defaultValue": "false" -}]} \ No newline at end of file +{ + "properties": [ + { + "name": "spring.guice.dedup", + "type": "java.lang.Boolean", + "description": "When using `@EnableGuiceModules`, if a Spring Bean and a Guice Binding both exist for the same type and Qualifier, the Spring Bean will be kept and the Guice Binding discarded.", + "defaultValue": "false" + }, + { + "name": "spring.guice.autowireJIT", + "type": "java.lang.Boolean", + "description": "When enabled, beans without explicit definitions will be created using Guice just-in-time bindings. Otherwise, it will fail with UnsatisfiedDependencyException.", + "defaultValue": "true" + } + ] +} \ No newline at end of file diff --git a/src/test/java/org/springframework/guice/JustInTimeBindingTests.java b/src/test/java/org/springframework/guice/JustInTimeBindingTests.java new file mode 100644 index 0000000..8d4b3fa --- /dev/null +++ b/src/test/java/org/springframework/guice/JustInTimeBindingTests.java @@ -0,0 +1,61 @@ +package org.springframework.guice; + +import org.junit.After; +import org.junit.Test; +import org.springframework.beans.factory.UnsatisfiedDependencyException; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.guice.annotation.EnableGuiceModules; + +import javax.inject.Inject; + +import static org.junit.Assert.assertNotNull; + +public class JustInTimeBindingTests { + + @After + public void tearDown() { + System.clearProperty("spring.guice.autowireJIT"); + } + + @Test + public void springWithJustInTimeBinding() { + System.setProperty("spring.guice.autowireJIT", "true"); + assertNotNull(springGetFoo()); + } + + @Test(expected = UnsatisfiedDependencyException.class) + public void springWithoutJustInTimeBinding() { + System.setProperty("spring.guice.autowireJIT", "false"); + springGetFoo(); + } + + private Foo springGetFoo() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ModulesConfig.class); + context.getDefaultListableBeanFactory().registerBeanDefinition(Foo.class.getSimpleName(), new RootBeanDefinition(Foo.class)); + return context.getBean(Foo.class); + } + + @Configuration + @EnableGuiceModules + static class ModulesConfig { + + } + + + public static class Service { + } + + public static class Foo { + + Service service; + + @Inject + public Foo(Service service) { + this.service = service; + } + + } + +}