diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java index 4d7fcd880..366079f57 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java @@ -22,7 +22,6 @@ import com.google.gson.Gson; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; @@ -39,6 +38,7 @@ import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.annotation.AnnotationConfigUtils; import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; +import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.format.support.DefaultFormattingConversionService; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -108,10 +108,13 @@ public class ContextFunctionCatalogInitializer } if (!context.getBeanFactory().containsBean( - AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { + AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { + // Switch off the ConfigurationClassPostProcessor context.registerBean( - AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME, - AutowiredAnnotationBeanPostProcessor.class); + AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME, + DummyProcessor.class, () -> new DummyProcessor()); + // But switch on other annotation processing + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); } if (!context.getBeanFactory() .containsBean(ConfigurationBeanFactoryMetadata.BEAN_NAME)) { @@ -220,5 +223,9 @@ public class ContextFunctionCatalogInitializer } } + + public static class DummyProcessor { + public void setMetadataReaderFactory(MetadataReaderFactory obj) {} + } } diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/BeanFactoryFunctionCatalogTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/BeanFactoryFunctionCatalogTests.java index 87bb5e378..cf7f4dc6c 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/BeanFactoryFunctionCatalogTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/BeanFactoryFunctionCatalogTests.java @@ -16,25 +16,24 @@ package org.springframework.cloud.function.context.config; -import static org.assertj.core.api.Assertions.assertThat; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; -import java.util.concurrent.atomic.AtomicStampedReference; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import org.junit.Test; -import org.reactivestreams.Publisher; + import org.springframework.cloud.function.context.FunctionRegistration; import org.springframework.cloud.function.context.FunctionType; import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration.BeanFactoryFunctionCatalog; import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration.ContextFunctionRegistry; +import static org.assertj.core.api.Assertions.assertThat; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializerTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializerTests.java index e21871571..9abdea6b2 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializerTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializerTests.java @@ -18,7 +18,9 @@ package org.springframework.cloud.function.context.config; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; @@ -26,10 +28,13 @@ import java.util.function.Supplier; import com.google.gson.Gson; import org.junit.After; +import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.function.context.FunctionCatalog; import org.springframework.cloud.function.context.FunctionRegistration; import org.springframework.cloud.function.context.FunctionType; @@ -37,6 +42,8 @@ import org.springframework.cloud.function.context.catalog.FunctionInspector; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.annotation.Bean; import org.springframework.context.support.GenericApplicationContext; +import org.springframework.core.env.MapPropertySource; +import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -66,6 +73,40 @@ public class ContextFunctionCatalogInitializerTests { assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class); assertThat((Function) catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); + } + + @Test + public void properties() { + create(PropertiesConfiguration.class, "app.greeting=hello"); + assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class); + @SuppressWarnings("unchecked") + Function, Flux> function = (Function, Flux>) catalog + .lookup(Function.class, "function"); + assertThat(function).isInstanceOf(Function.class); + assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("hello foo"); + } + + @Test + public void value() { + create(ValueConfiguration.class, "app.greeting=hello"); + assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class); + @SuppressWarnings("unchecked") + Function, Flux> function = (Function, Flux>) catalog + .lookup(Function.class, "function"); + assertThat(function).isInstanceOf(Function.class); + assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("hello foo"); + } + + @Test + @Ignore + public void compose() { + create(SimpleConfiguration.class); + assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class); + @SuppressWarnings("unchecked") + Supplier> supplier = (Supplier>) catalog + .lookup(Supplier.class, "supplier|function"); + assertThat(supplier).isInstanceOf(Supplier.class); + assertThat(supplier.get().blockFirst()).isEqualTo("HELLO"); // TODO: support for function composition } @@ -153,6 +194,17 @@ public class ContextFunctionCatalogInitializerTests { private void create(ApplicationContextInitializer[] types, String... props) { context = new GenericApplicationContext(); + Map map = new HashMap<>(); + for (String prop : props) { + String[] array = StringUtils.delimitedListToStringArray(prop, "="); + String key = array[0]; + String value = array.length > 1 ? array[1] : ""; + map.put(key, value); + } + if (!map.isEmpty()) { + context.getEnvironment().getPropertySources() + .addFirst(new MapPropertySource("testProperties", map)); + } for (ApplicationContextInitializer type : types) { type.initialize(context); } @@ -222,6 +274,56 @@ public class ContextFunctionCatalogInitializerTests { } } + @ConfigurationProperties("app") + protected static class PropertiesConfiguration + implements ApplicationContextInitializer { + + private String greeting; + + public String getGreeting() { + return this.greeting; + } + + public void setGreeting(String greeting) { + this.greeting = greeting; + } + + @Override + public void initialize(GenericApplicationContext context) { + context.registerBean("function", FunctionRegistration.class, + () -> new FunctionRegistration<>(function()).type( + FunctionType.from(String.class).to(String.class).getType())); + context.registerBean(PropertiesConfiguration.class, () -> this); + } + + @Bean + public Function function() { + return value -> greeting + " " + value; + } + + } + + protected static class ValueConfiguration + implements ApplicationContextInitializer { + + @Value("${app.greeting}") + private String greeting; + + @Override + public void initialize(GenericApplicationContext context) { + context.registerBean("function", FunctionRegistration.class, + () -> new FunctionRegistration<>(function()).type( + FunctionType.from(String.class).to(String.class).getType())); + context.registerBean(ValueConfiguration.class, () -> this); + } + + @Bean + public Function function() { + return value -> greeting + " " + value; + } + + } + protected static class GsonConfiguration implements ApplicationContextInitializer {