diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfiguration.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfiguration.java index 681c3d12f..43fafdf8d 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfiguration.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfiguration.java @@ -36,7 +36,7 @@ import com.google.gson.Gson; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; @@ -68,6 +68,7 @@ import org.springframework.core.type.StandardMethodMetadata; * @author Mark Fisher * @author Oleg Zhurakousky * @author Artem Bilan + * @author Anshul Mehra */ @Configuration @ConditionalOnMissingBean(FunctionCatalog.class) @@ -85,7 +86,7 @@ public class ContextFunctionCatalogAutoConfiguration { protected static class BeanFactoryFunctionCatalog extends AbstractComposableFunctionRegistry - implements InitializingBean, BeanFactoryAware { + implements SmartInitializingSingleton, BeanFactoryAware { private ApplicationEventPublisher applicationEventPublisher; @@ -96,18 +97,17 @@ public class ContextFunctionCatalogAutoConfiguration { * late as possible in the lifecycle. */ @Override - @SuppressWarnings("rawtypes") - public void afterPropertiesSet() throws Exception { + public void afterSingletonsInstantiated() { Map supplierBeans = this.beanFactory - .getBeansOfType(Supplier.class); + .getBeansOfType(Supplier.class); Map functionBeans = this.beanFactory - .getBeansOfType(Function.class); + .getBeansOfType(Function.class); Map consumerBeans = this.beanFactory - .getBeansOfType(Consumer.class); + .getBeansOfType(Consumer.class); Map functionRegistrationBeans = this.beanFactory - .getBeansOfType(FunctionRegistration.class); + .getBeansOfType(FunctionRegistration.class); this.doMerge(functionRegistrationBeans, consumerBeans, supplierBeans, - functionBeans); + functionBeans); } @Override @@ -227,7 +227,6 @@ public class ContextFunctionCatalogAutoConfiguration { registrations.forEach(registration -> register(registration, targets.get(registration.getTarget()))); } - } private static class PreferGsonOrMissingJacksonCondition extends AnyNestedCondition { diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfigurationTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfigurationTests.java index 57340ac0d..7a4b97e48 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfigurationTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfigurationTests.java @@ -35,7 +35,6 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.AbstractFactoryBean; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; @@ -49,6 +48,7 @@ import org.springframework.cloud.function.compiler.CompiledFunctionFactory; import org.springframework.cloud.function.compiler.FunctionCompiler; import org.springframework.cloud.function.context.FunctionCatalog; import org.springframework.cloud.function.context.FunctionRegistration; +import org.springframework.cloud.function.context.FunctionRegistry; import org.springframework.cloud.function.context.catalog.FunctionInspector; import org.springframework.cloud.function.inject.FooConfiguration; import org.springframework.cloud.function.scan.ScannedFunction; @@ -58,11 +58,14 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.core.env.Environment; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.DescriptiveResource; import org.springframework.core.io.FileSystemResource; +import org.springframework.lang.Nullable; import org.springframework.messaging.Message; import org.springframework.messaging.support.MessageBuilder; +import org.springframework.stereotype.Component; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; import org.springframework.util.StreamUtils; @@ -73,6 +76,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Dave Syer * @author Artem Bilan * @author Oleg Zhurakousky + * @author Anshul Mehra */ public class ContextFunctionCatalogAutoConfigurationTests { @@ -290,7 +294,7 @@ public class ContextFunctionCatalogAutoConfigurationTests { .isAssignableFrom(Mono.class); } - @Test(expected = BeanCreationException.class) + @Test(expected = IllegalArgumentException.class) public void monoToMonoNonVoidFunction() { create(MonoToMonoNonVoidConfiguration.class); } @@ -589,6 +593,17 @@ public class ContextFunctionCatalogAutoConfigurationTests { assertThat(f.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO-bar"); } + @Test + public void functionCatalogDependentBeanFactoryPostProcessor() { + create(new Class[]{ComponentFunctionConfiguration.class, AppendFunction.class}); + assertThat(this.context.getBean("appendFunction")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "appendFunction")) + .isInstanceOf(Function.class); + Function, Flux> f = this.catalog.lookup(Function.class, + "appendFunction"); + assertThat(f.apply(Flux.just("World")).blockFirst()).isEqualTo("Hello World"); + } + private void create(Class type, String... props) { create(new Class[] { type }, props); } @@ -643,6 +658,35 @@ public class ContextFunctionCatalogAutoConfigurationTests { } + @EnableAutoConfiguration + @Configuration + protected static class ComponentFunctionConfiguration { + @Bean + public String value() { + return "Hello "; + } + + @Bean + public BeanFactoryPostProcessor someBeanFactoryPostProcessor(Environment environment, + @Nullable FunctionRegistry functionCatalog, @Nullable FunctionInspector inspector) { + return beanFactory -> { }; + } + } + + @Component("appendFunction") + public static class AppendFunction implements Function { + private String value; + + public AppendFunction(String value) { + this.value = value; + } + + @Override + public String apply(String s) { + return this.value + s; + } + } + @EnableAutoConfiguration @Configuration protected static class DependencyInjectionConfiguration {