Discover function type from FactoryBean
* Fix spring-integration sample * Added discoverFunctionTypeFromClass() method to FunctionTypeUtils * A `FactoryBean` may produce a function instance as well. Add a logic into `BeanFactoryAwareFunctionRegistry` to discover a function type from the `FactoryBean.getObjectType()`
This commit is contained in:
committed by
Artem Bilan
parent
bdd4320a59
commit
97bea81836
@@ -47,6 +47,7 @@ import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.cloud.function.context.FunctionCatalog;
|
||||
@@ -188,6 +189,10 @@ public class BeanFactoryAwareFunctionRegistry
|
||||
boolean beanDefinitionExists = false;
|
||||
for (int i = 0; i < names.length && !beanDefinitionExists; i++) {
|
||||
beanDefinitionExists = this.applicationContext.getBeanFactory().containsBeanDefinition(names[i]);
|
||||
if (this.applicationContext.containsBean("&" + names[i])) {
|
||||
Class<?> objectType = this.applicationContext.getBean("&" + names[i], FactoryBean.class).getObjectType();
|
||||
return FunctionTypeUtils.discoverFunctionTypeFromClass(objectType);
|
||||
}
|
||||
}
|
||||
if (!beanDefinitionExists) {
|
||||
logger.info("BeanDefinition for function name(s) '" + Arrays.asList(names) +
|
||||
@@ -430,7 +435,9 @@ public class BeanFactoryAwareFunctionRegistry
|
||||
|
||||
FunctionInvocationWrapper(Object target, Type functionType, String functionDefinition, String... acceptedOutputMimeTypes) {
|
||||
this.target = target;
|
||||
this.composed = !target.getClass().getName().contains("EnhancerBySpringCGLIB") && target.getClass().getDeclaredFields().length > 1;
|
||||
this.composed = !target.getClass().getName().contains("$$EnhancerBySpringCGLIB")
|
||||
&& !AopUtils.isAopProxy(target) && !AopUtils.isJdkDynamicProxy(target)
|
||||
&& target.getClass().getDeclaredFields().length > 1;
|
||||
this.functionType = functionType;
|
||||
this.acceptedOutputMimeTypes = acceptedOutputMimeTypes;
|
||||
this.functionDefinition = functionDefinition;
|
||||
|
||||
@@ -105,7 +105,34 @@ public final class FunctionTypeUtils {
|
||||
return methods.get(0);
|
||||
}
|
||||
|
||||
public static Type getFunctionTypeFromFunctionMethod(Method functionMethod) {
|
||||
public static Type discoverFunctionTypeFromClass(Class<?> functionalClass) {
|
||||
Assert.isTrue(isFunctional(functionalClass), "Type must be one of Supplier, Function or Consumer");
|
||||
Type[] generics = functionalClass.getGenericInterfaces();
|
||||
if (ObjectUtils.isEmpty(generics)) {
|
||||
return functionalClass;
|
||||
}
|
||||
else {
|
||||
for (Type generic : generics) {
|
||||
if (generic instanceof ParameterizedType) {
|
||||
Class<?> rawClsss = (Class<?>) ((ParameterizedType) generic).getRawType();
|
||||
if (rawClsss.isAssignableFrom(Function.class)
|
||||
|| rawClsss.isAssignableFrom(Consumer.class)
|
||||
|| rawClsss.isAssignableFrom(Supplier.class)) {
|
||||
return generic;
|
||||
}
|
||||
else {
|
||||
return discoverFunctionTypeFromClass(rawClsss);
|
||||
}
|
||||
}
|
||||
else {
|
||||
return discoverFunctionTypeFromClass((Class<?>) generic);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Type discoverFunctionTypeFromFunctionMethod(Method functionMethod) {
|
||||
Assert.isTrue(
|
||||
functionMethod.getName().equals("apply") ||
|
||||
functionMethod.getName().equals("accept") ||
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.cloud.function.context.catalog;
|
||||
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
@@ -30,6 +31,9 @@ import reactor.core.publisher.Mono;
|
||||
import reactor.util.function.Tuple2;
|
||||
import reactor.util.function.Tuple3;
|
||||
|
||||
import org.springframework.cloud.function.context.FunctionType;
|
||||
import org.springframework.messaging.Message;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
@@ -90,6 +94,26 @@ public class FunctionTypeUtilsTests {
|
||||
assertThat(outputCount).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionTypeByClassDiscovery() {
|
||||
FunctionType type = FunctionType.of(FunctionTypeUtils.discoverFunctionTypeFromClass(Function.class));
|
||||
assertThat(type.getInputType()).isAssignableFrom(Object.class);
|
||||
|
||||
type = FunctionType.of(FunctionTypeUtils.discoverFunctionTypeFromClass(MessageFunction.class));
|
||||
assertThat(type.getInputType()).isAssignableFrom(String.class);
|
||||
assertThat(type.getOutputType()).isAssignableFrom(String.class);
|
||||
|
||||
type = FunctionType.of(FunctionTypeUtils.discoverFunctionTypeFromClass(MyMessageFunction.class));
|
||||
assertThat(type.getInputType()).isAssignableFrom(String.class);
|
||||
assertThat(type.getOutputType()).isAssignableFrom(String.class);
|
||||
|
||||
type = FunctionType.of(FunctionTypeUtils.discoverFunctionTypeFromClass(MessageConsumer.class));
|
||||
assertThat(type.getInputType()).isAssignableFrom(String.class);
|
||||
|
||||
type = FunctionType.of(FunctionTypeUtils.discoverFunctionTypeFromClass(MyMessageConsumer.class));
|
||||
assertThat(type.getInputType()).isAssignableFrom(String.class);
|
||||
}
|
||||
|
||||
// @Test
|
||||
// public void testInputTypeByIndex() throws Exception {
|
||||
// Type functionType = getReturnType("function");
|
||||
@@ -163,4 +187,22 @@ public class FunctionTypeUtilsTests {
|
||||
private Type getReturnType(String methodName) throws Exception {
|
||||
return FunctionTypeUtilsTests.class.getDeclaredMethod(methodName).getGenericReturnType();
|
||||
}
|
||||
|
||||
//============
|
||||
|
||||
private interface MessageFunction<T> extends Function<Message<String>, Message<String>> {
|
||||
|
||||
}
|
||||
|
||||
private interface MyMessageFunction extends MessageFunction<Date> {
|
||||
|
||||
}
|
||||
|
||||
private interface MessageConsumer<T> extends Consumer<Message<String>> {
|
||||
|
||||
}
|
||||
|
||||
private interface MyMessageConsumer extends MessageConsumer<Date> {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user