diff --git a/spring-cloud-function-context/pom.xml b/spring-cloud-function-context/pom.xml
index d182403c7..757fe4d27 100644
--- a/spring-cloud-function-context/pom.xml
+++ b/spring-cloud-function-context/pom.xml
@@ -26,6 +26,10 @@
spring-cloud-function-core
${spring-cloud-function.version}
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
org.springframework.boot
spring-boot-configuration-processor
diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/ContextFunctionCatalogAutoConfiguration.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/ContextFunctionCatalogAutoConfiguration.java
index ac1911c97..4d8d8f1cd 100644
--- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/ContextFunctionCatalogAutoConfiguration.java
+++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/ContextFunctionCatalogAutoConfiguration.java
@@ -15,13 +15,26 @@
*/
package org.springframework.cloud.function.context;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.support.SimpleBeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -29,6 +42,12 @@ import org.springframework.cloud.function.registry.DefaultFunctionRegistryAutoCo
import org.springframework.cloud.function.registry.FunctionCatalog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.core.ResolvableType;
+import org.springframework.core.type.StandardMethodMetadata;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ClassUtils;
+
+import reactor.core.publisher.Flux;
@Configuration
@ConditionalOnClass(ApplicationContextFunctionCatalog.class)
@@ -48,4 +67,195 @@ public class ContextFunctionCatalogAutoConfiguration {
return new ApplicationContextFunctionCatalog(functions, consumers, suppliers);
}
+ @Component
+ public static class ContextFunctionPostProcessor
+ implements BeanFactoryPostProcessor, BeanDefinitionRegistryPostProcessor {
+
+ private BeanDefinitionRegistry registry;
+
+ private BeanDefinitionRegistry targets = new SimpleBeanDefinitionRegistry();
+
+ @Override
+ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)
+ throws BeansException {
+ this.registry = registry;
+ }
+
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory factory)
+ throws BeansException {
+ for (String name : factory.getBeanDefinitionNames()) {
+ if (isGenericFunction(factory, name)) {
+ wrapFunction(factory, name);
+ }
+ else if (isGenericSupplier(factory, name)) {
+ wrapSupplier(factory, name);
+ }
+ }
+ }
+
+ private boolean isGenericFunction(ConfigurableListableBeanFactory factory,
+ String name) {
+ return factory.isTypeMatch(name,
+ ResolvableType.forClassWithGenerics(Function.class, Flux.class,
+ Flux.class))
+ && !factory.isTypeMatch(name,
+ ResolvableType.forClassWithGenerics(Function.class,
+ ResolvableType.forClassWithGenerics(Flux.class,
+ String.class),
+ ResolvableType.forClassWithGenerics(Flux.class,
+ String.class)));
+ }
+
+ private boolean isGenericSupplier(ConfigurableListableBeanFactory factory,
+ String name) {
+ return factory.isTypeMatch(name,
+ ResolvableType.forClassWithGenerics(Supplier.class, Flux.class))
+ && !factory.isTypeMatch(name,
+ ResolvableType.forClassWithGenerics(Supplier.class,
+ ResolvableType.forClassWithGenerics(Flux.class,
+ String.class)));
+ }
+
+ private void wrapFunction(ConfigurableListableBeanFactory factory, String name) {
+ BeanDefinition definition = registry.getBeanDefinition(name);
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder
+ .genericBeanDefinition(ProxyFunction.class);
+ builder.addPropertyValue("delegate", definition);
+ builder.addPropertyValue("name", name);
+ targets.registerBeanDefinition(name, definition);
+ builder.addPropertyValue("registry", targets);
+ registry.registerBeanDefinition(name, builder.getRawBeanDefinition());
+ }
+
+ private void wrapSupplier(ConfigurableListableBeanFactory factory, String name) {
+ BeanDefinition definition = registry.getBeanDefinition(name);
+ BeanDefinitionBuilder builder = BeanDefinitionBuilder
+ .genericBeanDefinition(ProxySupplier.class);
+ builder.addPropertyValue("delegate", definition);
+ builder.addPropertyValue("name", name);
+ targets.registerBeanDefinition(name, definition);
+ builder.addPropertyValue("registry", targets);
+ registry.registerBeanDefinition(name, builder.getRawBeanDefinition());
+ }
+ }
+}
+
+class ProxyFunction implements Function, Flux> {
+
+ private ObjectMapper mapper;
+
+ private Function, Flux