Allow filtering of modules before initialization

Alternative for #111
This commit is contained in:
Niklas Herder
2023-06-19 16:13:06 +02:00
committed by Dave Syer
parent b4048a24c0
commit b202e964a2
4 changed files with 70 additions and 1 deletions

View File

@@ -112,6 +112,12 @@ public static class TestConfig {
The `Service` was defined in the Guice module `MyModule`, and then it
was be bound to the autowired `spam()` method when Spring started.
### Filtering out modules from startup of ApplicationContext
In certain cases you might need to ensure that some modules are not configured at all, even though they might not be present in the final `ApplicationContext`.
This might be due to external code that may be hard to change that cause side effects at binding time, or for other reasons.
To ensure this you can define a `ModuleFilter` bean that will be applied for filtering the list of modules in the Guice context before they are touched by the Spring-Guice bridge. This will ensure that no `configure()` methods are called on the filtered modules.
## Configuration Class Enhancements
Note that the `Module` bean definition in the example above is

View File

@@ -0,0 +1,10 @@
package org.springframework.guice.annotation;
import com.google.inject.Module;
@FunctionalInterface
public interface ModuleFilter {
boolean filter(Module module);
}

View File

@@ -125,8 +125,18 @@ class ModuleRegistryConfiguration implements BeanDefinitionRegistryPostProcessor
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
Map<String, ModuleFilter> moduleFilters = ((ConfigurableListableBeanFactory) registry)
.getBeansOfType(ModuleFilter.class);
if (moduleFilters.size() > 1) {
throw new IllegalStateException(
"You can only define zero or one ModuleFilter implementation. Implementations found: "
+ String.join(",", moduleFilters.keySet()));
}
ModuleFilter moduleFilter = moduleFilters.values().stream().findFirst().orElse(module -> true);
List<Module> modules = new ArrayList<>(
((ConfigurableListableBeanFactory) registry).getBeansOfType(Module.class).values());
((ConfigurableListableBeanFactory) registry).getBeansOfType(Module.class).values()).stream()
.filter(moduleFilter::filter).collect(Collectors.toList());
SpringModule module = new SpringModule((ConfigurableListableBeanFactory) registry,
this.enableJustInTimeBinding);
modules.add(module);

View File

@@ -75,6 +75,14 @@ public class EnableGuiceModulesTests {
context.close();
}
@Test
public void moduleBeanFiltersOutModules() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
FilteringModuleBeanConfig.class);
assertThat(context.getBean(Foo.class)).isNotNull();
context.close();
}
@Test
public void testInjectorCreationDoesNotCauseCircularDependencyError() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);
@@ -151,6 +159,32 @@ public class EnableGuiceModulesTests {
}
@Configuration(proxyBeanMethods = false)
@EnableGuiceModules
protected static class FilteringModuleBeanConfig {
@Bean
public static MyModule2 module2() {
return new MyModule2();
}
@Bean
public static MyModule module() {
return new MyModule();
}
@Bean
public Foo service(Service service) {
return new Foo(service);
}
@Bean
ModuleFilter moduleFilter() {
return module -> !(module instanceof MyModule2);
}
}
protected static class MyModule extends AbstractModule {
@Override
@@ -160,6 +194,15 @@ public class EnableGuiceModulesTests {
}
protected static class MyModule2 extends AbstractModule {
@Override
protected void configure() {
throw new RuntimeException("This should not be called when filtered out!");
}
}
public static class SpringProvidedBean {
public SpringProvidedBean(GuiceProvidedBean guiceProvidedBean) {