Add function type discovery method to FunctionTypeUtils
This commit is contained in:
@@ -29,13 +29,11 @@ import org.aopalliance.intercept.MethodInvocation;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||
import org.springframework.cloud.function.context.FunctionProperties;
|
||||
import org.springframework.cloud.function.context.FunctionRegistration;
|
||||
import org.springframework.cloud.function.context.FunctionType;
|
||||
import org.springframework.cloud.function.context.config.FunctionContextUtils;
|
||||
import org.springframework.cloud.function.context.config.RoutingFunction;
|
||||
import org.springframework.cloud.function.context.FunctionRegistry;
|
||||
import org.springframework.cloud.function.json.JsonMapper;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
@@ -44,6 +42,11 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.messaging.converter.CompositeMessageConverter;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Implementation of {@link FunctionRegistry} capable of discovering functioins in {@link BeanFactory}
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
*/
|
||||
public class BeanFactoryAwareFunctionRegistry extends SimpleFunctionRegistry implements ApplicationContextAware {
|
||||
|
||||
private GenericApplicationContext applicationContext;
|
||||
@@ -129,7 +132,7 @@ public class BeanFactoryAwareFunctionRegistry extends SimpleFunctionRegistry imp
|
||||
.getBean(functionName + FunctionRegistration.REGISTRATION_NAME_SUFFIX, FunctionRegistration.class);
|
||||
}
|
||||
else {
|
||||
functionType = this.discoverFunctionType(functionCandidate, functionName);
|
||||
functionType = FunctionTypeUtils.discoverFunctionType(functionCandidate, functionName, this.applicationContext);
|
||||
}
|
||||
if (functionRegistration == null) {
|
||||
functionRegistration = new FunctionRegistration(functionCandidate, functionName).type(functionType);
|
||||
@@ -171,47 +174,6 @@ public class BeanFactoryAwareFunctionRegistry extends SimpleFunctionRegistry imp
|
||||
return super.containsFunction(functionName) ? true : this.applicationContext.containsBean(functionName);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
Type discoverFunctionType(Object function, String functionName) {
|
||||
if (function instanceof RoutingFunction) {
|
||||
return FunctionType.of(FunctionContextUtils.findType(applicationContext.getBeanFactory(), functionName)).getType();
|
||||
}
|
||||
else if (function instanceof FunctionRegistration) {
|
||||
return ((FunctionRegistration) function).getType().getType();
|
||||
}
|
||||
boolean beanDefinitionExists = false;
|
||||
String functionBeanDefinitionName = this.discoverDefinitionName(functionName);
|
||||
beanDefinitionExists = this.applicationContext.getBeanFactory().containsBeanDefinition(functionBeanDefinitionName);
|
||||
if (this.applicationContext.containsBean("&" + functionName)) {
|
||||
Class<?> objectType = this.applicationContext.getBean("&" + functionName, FactoryBean.class)
|
||||
.getObjectType();
|
||||
return FunctionTypeUtils.discoverFunctionTypeFromClass(objectType);
|
||||
}
|
||||
// if (!beanDefinitionExists) {
|
||||
// logger.info("BeanDefinition for function name(s) '" + Arrays.asList(names) +
|
||||
// "' can not be located. FunctionType will be based on " + function.getClass());
|
||||
// }
|
||||
|
||||
Type type = FunctionTypeUtils.discoverFunctionTypeFromClass(function.getClass());
|
||||
if (beanDefinitionExists) {
|
||||
Type t = FunctionTypeUtils.getImmediateGenericType(type, 0);
|
||||
if (t == null || t == Object.class) {
|
||||
type = FunctionType.of(FunctionContextUtils.findType(this.applicationContext.getBeanFactory(), functionBeanDefinitionName)).getType();
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private String discoverDefinitionName(String functionDefinition) {
|
||||
String[] aliases = this.applicationContext.getAliases(functionDefinition);
|
||||
for (String alias : aliases) {
|
||||
if (this.applicationContext.getBeanFactory().containsBeanDefinition(alias)) {
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
return functionDefinition;
|
||||
}
|
||||
|
||||
private boolean isFunctionPojo(Object functionCandidate, String functionName) {
|
||||
return !functionCandidate.getClass().isSynthetic()
|
||||
&& !(functionCandidate instanceof Supplier)
|
||||
|
||||
@@ -36,7 +36,12 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.cloud.function.context.FunctionRegistration;
|
||||
import org.springframework.cloud.function.context.FunctionType;
|
||||
import org.springframework.cloud.function.context.config.FunctionContextUtils;
|
||||
import org.springframework.cloud.function.context.config.RoutingFunction;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -223,6 +228,33 @@ public final class FunctionTypeUtils {
|
||||
return inputType;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static Type discoverFunctionType(Object function, String functionName, GenericApplicationContext applicationContext) {
|
||||
if (function instanceof RoutingFunction) {
|
||||
return FunctionType.of(FunctionContextUtils.findType(applicationContext.getBeanFactory(), functionName)).getType();
|
||||
}
|
||||
else if (function instanceof FunctionRegistration) {
|
||||
return ((FunctionRegistration) function).getType().getType();
|
||||
}
|
||||
boolean beanDefinitionExists = false;
|
||||
String functionBeanDefinitionName = discoverDefinitionName(functionName, applicationContext);
|
||||
beanDefinitionExists = applicationContext.getBeanFactory().containsBeanDefinition(functionBeanDefinitionName);
|
||||
if (applicationContext.containsBean("&" + functionName)) {
|
||||
Class<?> objectType = applicationContext.getBean("&" + functionName, FactoryBean.class)
|
||||
.getObjectType();
|
||||
return FunctionTypeUtils.discoverFunctionTypeFromClass(objectType);
|
||||
}
|
||||
|
||||
Type type = FunctionTypeUtils.discoverFunctionTypeFromClass(function.getClass());
|
||||
if (beanDefinitionExists) {
|
||||
Type t = FunctionTypeUtils.getImmediateGenericType(type, 0);
|
||||
if (t == null || t == Object.class) {
|
||||
type = FunctionType.of(FunctionContextUtils.findType(applicationContext.getBeanFactory(), functionBeanDefinitionName)).getType();
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Type getOutputType(Type functionType) {
|
||||
assertSupportedTypes(functionType);
|
||||
@@ -291,34 +323,11 @@ public final class FunctionTypeUtils {
|
||||
return isOfType(type, Consumer.class);
|
||||
}
|
||||
|
||||
private static boolean isOfType(Type type, Class<?> cls) {
|
||||
if (type instanceof Class) {
|
||||
return cls.isAssignableFrom((Class<?>) type);
|
||||
}
|
||||
else if (type instanceof ParameterizedType) {
|
||||
return isOfType(((ParameterizedType) type).getRawType(), cls);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isMono(Type type) {
|
||||
type = extractReactiveType(type);
|
||||
return type == null ? false : type.getTypeName().startsWith("reactor.core.publisher.Mono");
|
||||
}
|
||||
|
||||
private static boolean isFunctional(Type type) {
|
||||
if (type instanceof ParameterizedType) {
|
||||
type = ((ParameterizedType) type).getRawType();
|
||||
Assert.isTrue(type instanceof Class<?>, "Must be one of Supplier, Function, Consumer"
|
||||
+ " or FunctionRegistration. Was " + type);
|
||||
}
|
||||
|
||||
Class<?> candidateType = (Class<?>) type;
|
||||
return Supplier.class.isAssignableFrom(candidateType)
|
||||
|| Function.class.isAssignableFrom(candidateType)
|
||||
|| Consumer.class.isAssignableFrom(candidateType);
|
||||
}
|
||||
|
||||
public static boolean isMultipleArgumentType(Type type) {
|
||||
if (type != null) {
|
||||
if (TypeResolver.resolveRawClass(type, null).isArray()) {
|
||||
@@ -350,12 +359,6 @@ public final class FunctionTypeUtils {
|
||||
ResolvableType.forMethodReturnType(functionalMethod)).getType();
|
||||
}
|
||||
break;
|
||||
// case 2:
|
||||
// ResolvableType canonicalParametersWrapper = fromTwoArityFunction(functionalMethod);
|
||||
// functionType = ResolvableType.forClassWithGenerics(Function.class,
|
||||
// canonicalParametersWrapper,
|
||||
// ResolvableType.forMethodReturnType(functionalMethod)).getType();
|
||||
// break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Functional method: " + functionalMethod + " is not supported");
|
||||
}
|
||||
@@ -366,6 +369,16 @@ public final class FunctionTypeUtils {
|
||||
return type.getTypeName().startsWith("reactor.util.function.Tuple");
|
||||
}
|
||||
|
||||
private static boolean isOfType(Type type, Class<?> cls) {
|
||||
if (type instanceof Class) {
|
||||
return cls.isAssignableFrom((Class<?>) type);
|
||||
}
|
||||
else if (type instanceof ParameterizedType) {
|
||||
return isOfType(((ParameterizedType) type).getRawType(), cls);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void assertSupportedTypes(Type type) {
|
||||
if (type instanceof ParameterizedType) {
|
||||
type = ((ParameterizedType) type).getRawType();
|
||||
@@ -392,4 +405,29 @@ public final class FunctionTypeUtils {
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private static String discoverDefinitionName(String functionDefinition, GenericApplicationContext applicationContext) {
|
||||
String[] aliases = applicationContext.getAliases(functionDefinition);
|
||||
for (String alias : aliases) {
|
||||
if (applicationContext.getBeanFactory().containsBeanDefinition(alias)) {
|
||||
return alias;
|
||||
}
|
||||
}
|
||||
return functionDefinition;
|
||||
}
|
||||
|
||||
private static boolean isFunctional(Type type) {
|
||||
if (type instanceof ParameterizedType) {
|
||||
type = ((ParameterizedType) type).getRawType();
|
||||
Assert.isTrue(type instanceof Class<?>, "Must be one of Supplier, Function, Consumer"
|
||||
+ " or FunctionRegistration. Was " + type);
|
||||
}
|
||||
|
||||
Class<?> candidateType = (Class<?>) type;
|
||||
return Supplier.class.isAssignableFrom(candidateType)
|
||||
|| Function.class.isAssignableFrom(candidateType)
|
||||
|| Consumer.class.isAssignableFrom(candidateType)
|
||||
|| BiFunction.class.isAssignableFrom(candidateType)
|
||||
|| BiConsumer.class.isAssignableFrom(candidateType);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user