From 1dda492d578d4d35487ff3e83757e4e4f9c0be8a Mon Sep 17 00:00:00 2001 From: Niklas Herder Date: Sat, 22 Jul 2023 12:22:02 +0200 Subject: [PATCH] Allow multiple ModuleFilter implementations --- README.md | 28 ++++++++++++++-- .../guice/annotation/ModuleFilter.java | 33 +++++++++++++++++-- .../ModuleRegistryConfiguration.java | 24 +++++++------- .../annotation/EnableGuiceModulesTests.java | 22 +++++++++++-- 4 files changed, 87 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index ad4b7b5..a7bb82b 100644 --- a/README.md +++ b/README.md @@ -114,9 +114,31 @@ 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. +In certain cases you might need to ensure that some modules are not configured at all, even though they will be absent from the final `ApplicationContext`. +This might be due to external code that may be hard to change that causes side effects at binding time, for example. +To ensure that these modules are not called at all you can define one or more`ModuleFilter` beans that will be applied to filter out modules from the context before they are touched by the Spring-Guice bridge. + +```java + +import org.springframework.context.annotation.Bean; +import org.springframework.guice.annotation.ModuleFilter; + +public static class TestConfig { + + + @Bean + public static MyModule myModule() { + return new MyModule(); + } + + @Bean + public ModuleFilter myFilter() { + return module -> !(module instanceof MyModule); + } +} + +``` +This will ensure that no `configure()` methods are called on the filtered modules. ## Configuration Class Enhancements diff --git a/src/main/java/org/springframework/guice/annotation/ModuleFilter.java b/src/main/java/org/springframework/guice/annotation/ModuleFilter.java index f65428b..abe3af5 100644 --- a/src/main/java/org/springframework/guice/annotation/ModuleFilter.java +++ b/src/main/java/org/springframework/guice/annotation/ModuleFilter.java @@ -1,10 +1,37 @@ +/* + * 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 + * + * https://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.annotation; +import java.util.function.Predicate; + import com.google.inject.Module; -@FunctionalInterface -public interface ModuleFilter { +import org.springframework.beans.factory.support.BeanDefinitionRegistry; - boolean filter(Module module); +/** + * A filter to remove {@link Module}:s from the context before any initialization code is + * run. If one implementation of this interface returns false from its + * {@link #test(Object)} method, the {@link Module} is removed. See + * {@link ModuleRegistryConfiguration#postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)} + * + * @author Niklas Herder + * + */ + +public interface ModuleFilter extends Predicate { } diff --git a/src/main/java/org/springframework/guice/annotation/ModuleRegistryConfiguration.java b/src/main/java/org/springframework/guice/annotation/ModuleRegistryConfiguration.java index 3ff4d4b..5e35730 100644 --- a/src/main/java/org/springframework/guice/annotation/ModuleRegistryConfiguration.java +++ b/src/main/java/org/springframework/guice/annotation/ModuleRegistryConfiguration.java @@ -125,18 +125,8 @@ class ModuleRegistryConfiguration implements BeanDefinitionRegistryPostProcessor @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { - - Map 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 modules = new ArrayList<>( - ((ConfigurableListableBeanFactory) registry).getBeansOfType(Module.class).values()).stream() - .filter(moduleFilter::filter).collect(Collectors.toList()); + List modules = filterModules(registry, + new ArrayList<>(((ConfigurableListableBeanFactory) registry).getBeansOfType(Module.class).values())); SpringModule module = new SpringModule((ConfigurableListableBeanFactory) registry, this.enableJustInTimeBinding); modules.add(module); @@ -178,6 +168,16 @@ class ModuleRegistryConfiguration implements BeanDefinitionRegistryPostProcessor registry.registerBeanDefinition("guiceInjectorInitializer", beanDefinition); } + private List filterModules(BeanDefinitionRegistry registry, List modules) { + Map moduleFilters = ((ConfigurableListableBeanFactory) registry) + .getBeansOfType(ModuleFilter.class); + Predicate moduleFilter = (m) -> true; + for (Predicate value : moduleFilters.values()) { + moduleFilter = moduleFilter.and(value); + } + return modules.stream().filter(moduleFilter).collect(Collectors.toList()); + } + @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) { diff --git a/src/test/java/org/springframework/guice/annotation/EnableGuiceModulesTests.java b/src/test/java/org/springframework/guice/annotation/EnableGuiceModulesTests.java index d04a5b9..85ad2e5 100644 --- a/src/test/java/org/springframework/guice/annotation/EnableGuiceModulesTests.java +++ b/src/test/java/org/springframework/guice/annotation/EnableGuiceModulesTests.java @@ -83,6 +83,14 @@ public class EnableGuiceModulesTests { context.close(); } + @Test + public void moduleBeanFiltersOutModulesWithMultipleFilters() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + FilteringModuleBeanConfig.class, PermissiveModuleFilterConfig.class); + assertThat(context.getBean(Foo.class)).isNotNull(); + context.close(); + } + @Test public void testInjectorCreationDoesNotCauseCircularDependencyError() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class); @@ -179,8 +187,18 @@ public class EnableGuiceModulesTests { } @Bean - ModuleFilter moduleFilter() { - return module -> !(module instanceof MyModule2); + static ModuleFilter moduleFilter() { + return (module) -> !(module instanceof MyModule2); + } + + } + + @Configuration + static class PermissiveModuleFilterConfig { + + @Bean + static ModuleFilter moduleFilter2() { + return (module) -> true; } }