Add FunctionFactoryMetadata interface for type discovery
The compiled functions implement that interface which means you can inspect the signature of the method that created them and discover its generic types.
This commit is contained in:
@@ -42,5 +42,11 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-function-compiler</artifactId>
|
||||
<version>${spring-cloud-function.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -51,6 +51,7 @@ import org.springframework.cloud.function.registry.FunctionCatalog;
|
||||
import org.springframework.cloud.function.support.FluxConsumer;
|
||||
import org.springframework.cloud.function.support.FluxFunction;
|
||||
import org.springframework.cloud.function.support.FluxSupplier;
|
||||
import org.springframework.cloud.function.support.FunctionFactoryMetadata;
|
||||
import org.springframework.cloud.function.support.FunctionUtils;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -391,7 +392,7 @@ public class ContextFunctionCatalogAutoConfiguration {
|
||||
private Class<?> findType(String name, AbstractBeanDefinition definition,
|
||||
ParamType paramType) {
|
||||
Object source = definition.getSource();
|
||||
Type param;
|
||||
Type param = null;
|
||||
// Start by assuming output -> Function
|
||||
int index = paramType.isOutput() ? 1 : 0;
|
||||
if (source instanceof StandardMethodMetadata) {
|
||||
@@ -422,18 +423,26 @@ public class ContextFunctionCatalogAutoConfiguration {
|
||||
if (resolvable != null) {
|
||||
param = resolvable.getGeneric(index).getGeneric(0).getType();
|
||||
}
|
||||
else {
|
||||
// TODO: compiled functions (only work as String -> String)
|
||||
if (paramType.isWrapper() && !Consumer.class.isAssignableFrom(definition.getBeanClass())) {
|
||||
return Flux.class;
|
||||
else if (registry instanceof BeanFactory) {
|
||||
Object bean = ((BeanFactory) registry).getBean(name);
|
||||
if (bean instanceof FunctionFactoryMetadata) {
|
||||
FunctionFactoryMetadata factory = (FunctionFactoryMetadata) bean;
|
||||
Type type = factory.getFactoryMethod().getGenericReturnType();
|
||||
param = extractType(type, paramType, index);
|
||||
}
|
||||
return String.class;
|
||||
}
|
||||
}
|
||||
if (param instanceof ParameterizedType) {
|
||||
ParameterizedType concrete = (ParameterizedType) param;
|
||||
param = concrete.getRawType();
|
||||
}
|
||||
if (param == null) {
|
||||
// Last ditch attempt to guess: Flux<String>
|
||||
if (paramType.isWrapper()) {
|
||||
return Flux.class;
|
||||
}
|
||||
return String.class;
|
||||
}
|
||||
return (Class<?>) param;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,12 +30,16 @@ import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.function.compiler.CompiledFunctionFactory;
|
||||
import org.springframework.cloud.function.compiler.FunctionCompiler;
|
||||
import org.springframework.cloud.function.test.GenericFunction;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
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.io.FileSystemResource;
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -143,12 +147,35 @@ public class ContextFunctionCatalogAutoConfigurationTests {
|
||||
assertThat(catalog.lookupFunction("other")).isInstanceOf(Function.class);
|
||||
}
|
||||
|
||||
private void create(Class<?>... types) {
|
||||
context = new SpringApplicationBuilder((Object[]) types).run();
|
||||
@Test
|
||||
public void compiledFunction() throws Exception {
|
||||
CompiledFunctionFactory<Function<String, String>> compiled = new FunctionCompiler<String, String>(
|
||||
String.class.getName()).compile("foos", "v -> v.toUpperCase()", "String",
|
||||
"String");
|
||||
FileSystemResource resource = new FileSystemResource("target/foos.fun");
|
||||
StreamUtils.copy(compiled.getGeneratedClassBytes(), resource.getOutputStream());
|
||||
create(EmptyConfiguration.class,
|
||||
"spring.cloud.function.import.foos.location=file:./target/foos.fun");
|
||||
assertThat(context.getBean("foos")).isInstanceOf(Function.class);
|
||||
assertThat(catalog.lookupFunction("foos")).isInstanceOf(Function.class);
|
||||
assertThat(inspector.getInputWrapper("foos")).isEqualTo(String.class);
|
||||
}
|
||||
|
||||
private void create(Class<?> type, String... props) {
|
||||
create(new Class<?>[] { type }, props);
|
||||
}
|
||||
|
||||
private void create(Class<?>[] types, String... props) {
|
||||
context = new SpringApplicationBuilder((Object[]) types).properties(props).run();
|
||||
catalog = context.getBean(InMemoryFunctionCatalog.class);
|
||||
inspector = context.getBean(FunctionInspector.class);
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@Configuration
|
||||
protected static class EmptyConfiguration {
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@Configuration
|
||||
protected static class SimpleConfiguration {
|
||||
@@ -188,7 +215,7 @@ public class ContextFunctionCatalogAutoConfigurationTests {
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@Configuration
|
||||
@ComponentScan(basePackageClasses=GenericFunction.class)
|
||||
@ComponentScan(basePackageClasses = GenericFunction.class)
|
||||
protected static class ComponentScanConfiguration {
|
||||
}
|
||||
|
||||
@@ -237,4 +264,3 @@ public class ContextFunctionCatalogAutoConfigurationTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user