diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ApplicationRunner.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ApplicationRunner.java index 02a10c2fa..cb1f4bdf8 100644 --- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ApplicationRunner.java +++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ApplicationRunner.java @@ -16,8 +16,10 @@ package org.springframework.cloud.function.deployer; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.UUID; import javax.annotation.PreDestroy; @@ -144,6 +146,28 @@ public class ApplicationRunner { return false; } + /** + * List the bean names in the application context for a given type (by its fully qualified name). + * + * @param type the name of the type (Class) + * @return the bean names of that type + */ + public Set getBeanNames(String type) { + if (this.app != null) { + Expression parsed = new SpelExpressionParser() + .parseExpression("context.getBeansOfType(T(" + type + "))"); + try { + @SuppressWarnings("unchecked") + Map beans = (Map) parsed + .getValue(this.app); + return beans.keySet(); + } + catch (Exception e) { + } + } + return Collections.emptySet(); + } + public Object evaluate(String expression, Object root, Object... attrs) { Expression parsed = new SpelExpressionParser(this.config) .parseExpression(expression); diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionCreatorConfiguration.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionCreatorConfiguration.java index 4eaf821eb..908cf70b5 100644 --- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionCreatorConfiguration.java +++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionCreatorConfiguration.java @@ -25,7 +25,9 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Set; import java.util.StringTokenizer; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -114,7 +116,7 @@ class FunctionCreatorConfiguration { "Locating function from " + Arrays.asList(properties.getLocation())); this.creator = new BeanCreator(urls); this.creator.run(properties.getMain()); - Arrays.stream(properties.getBean()).map(this.creator::create).sequential() + Arrays.stream(functionNames()).map(this.creator::create).sequential() .forEach(this.creator::register); if (properties.getName().contains("|")) { // A composite function has to be explicitly registered before it is @@ -129,6 +131,13 @@ class FunctionCreatorConfiguration { } } + private String[] functionNames() { + if (properties.getBean() != null && properties.getBean().length > 0) { + return properties.getBean(); + } + return this.creator.getFunctionNames(); + } + @PreDestroy public void close() { if (this.creator != null) { @@ -375,6 +384,38 @@ class FunctionCreatorConfiguration { } } + public String[] getFunctionNames() { + Set list = new LinkedHashSet<>(); + ClassLoader contextClassLoader = ClassUtils + .overrideThreadContextClassLoader(functionClassLoader); + try { + if (this.runner.containsBean(FunctionCatalog.class.getName())) { + Object catalog = this.runner.getBean(FunctionCatalog.class.getName()); + @SuppressWarnings("unchecked") + Set functions = (Set) this.runner + .evaluate("getNames(#type)", catalog, "type", Function.class); + list.addAll(functions); + @SuppressWarnings("unchecked") + Set consumers = (Set) this.runner + .evaluate("getNames(#type)", catalog, "type", Consumer.class); + list.addAll(consumers); + @SuppressWarnings("unchecked") + Set suppliers = (Set) this.runner + .evaluate("getNames(#type)", catalog, "type", Supplier.class); + list.addAll(suppliers); + } + if (list.isEmpty()) { + list.addAll(this.runner.getBeanNames(Function.class.getName())); + list.addAll(this.runner.getBeanNames(Consumer.class.getName())); + list.addAll(this.runner.getBeanNames(Supplier.class.getName())); + } + return list.toArray(new String[0]); + } + finally { + ClassUtils.overrideThreadContextClassLoader(contextClassLoader); + } + } + public Object create(String type) { ClassLoader contextClassLoader = ClassUtils .overrideThreadContextClassLoader(functionClassLoader); diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionProperties.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionProperties.java index f67f9b080..39532752a 100644 --- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionProperties.java +++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionProperties.java @@ -95,9 +95,5 @@ public class FunctionProperties { throw new IllegalStateException( "No archive location provided, please configure function.location as a jar or directory."); } - if (bean.length == 0) { - throw new IllegalStateException( - "No function bean locator provided, please configure function.bean as a bean name or class name."); - } } } diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/ApplicationRunnerTests.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/ApplicationRunnerTests.java index 369988309..a78b5d3c5 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/ApplicationRunnerTests.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/ApplicationRunnerTests.java @@ -20,6 +20,7 @@ import org.junit.Ignore; import org.junit.Test; import org.springframework.cloud.function.context.FunctionCatalog; +import org.springframework.cloud.function.context.FunctionRegistration; import org.springframework.cloud.function.test.Doubler; import org.springframework.cloud.function.test.FunctionApp; import org.springframework.cloud.function.test.FunctionRegistrar; @@ -43,14 +44,13 @@ public class ApplicationRunnerTests { } @Test - @Ignore // related to boot 2.1 no bean override change public void functional() { ApplicationRunner runner = new ApplicationRunner(getClass().getClassLoader(), FunctionRegistrar.class.getName()); runner.run(); - assertThat(runner.containsBean(Doubler.class.getName())).isTrue(); - assertThat(runner.getBean(Doubler.class.getName())).isNotNull(); + assertThat(runner.containsBean(Doubler.class.getName())).isFalse(); assertThat(runner.getBean(FunctionCatalog.class.getName())).isNotNull(); + assertThat(runner.getBeanNames(FunctionRegistration.class.getName())).hasSize(2); runner.close(); } }