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.aop.framework.ProxyFactory;
|
||||||
import org.springframework.beans.BeansException;
|
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.beans.factory.annotation.BeanFactoryAnnotationUtils;
|
||||||
import org.springframework.cloud.function.context.FunctionProperties;
|
import org.springframework.cloud.function.context.FunctionProperties;
|
||||||
import org.springframework.cloud.function.context.FunctionRegistration;
|
import org.springframework.cloud.function.context.FunctionRegistration;
|
||||||
import org.springframework.cloud.function.context.FunctionType;
|
import org.springframework.cloud.function.context.FunctionRegistry;
|
||||||
import org.springframework.cloud.function.context.config.FunctionContextUtils;
|
|
||||||
import org.springframework.cloud.function.context.config.RoutingFunction;
|
|
||||||
import org.springframework.cloud.function.json.JsonMapper;
|
import org.springframework.cloud.function.json.JsonMapper;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
@@ -44,6 +42,11 @@ import org.springframework.core.convert.ConversionService;
|
|||||||
import org.springframework.messaging.converter.CompositeMessageConverter;
|
import org.springframework.messaging.converter.CompositeMessageConverter;
|
||||||
import org.springframework.util.StringUtils;
|
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 {
|
public class BeanFactoryAwareFunctionRegistry extends SimpleFunctionRegistry implements ApplicationContextAware {
|
||||||
|
|
||||||
private GenericApplicationContext applicationContext;
|
private GenericApplicationContext applicationContext;
|
||||||
@@ -129,7 +132,7 @@ public class BeanFactoryAwareFunctionRegistry extends SimpleFunctionRegistry imp
|
|||||||
.getBean(functionName + FunctionRegistration.REGISTRATION_NAME_SUFFIX, FunctionRegistration.class);
|
.getBean(functionName + FunctionRegistration.REGISTRATION_NAME_SUFFIX, FunctionRegistration.class);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
functionType = this.discoverFunctionType(functionCandidate, functionName);
|
functionType = FunctionTypeUtils.discoverFunctionType(functionCandidate, functionName, this.applicationContext);
|
||||||
}
|
}
|
||||||
if (functionRegistration == null) {
|
if (functionRegistration == null) {
|
||||||
functionRegistration = new FunctionRegistration(functionCandidate, functionName).type(functionType);
|
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);
|
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) {
|
private boolean isFunctionPojo(Object functionCandidate, String functionName) {
|
||||||
return !functionCandidate.getClass().isSynthetic()
|
return !functionCandidate.getClass().isSynthetic()
|
||||||
&& !(functionCandidate instanceof Supplier)
|
&& !(functionCandidate instanceof Supplier)
|
||||||
|
|||||||
@@ -36,7 +36,12 @@ import org.apache.commons.logging.LogFactory;
|
|||||||
import org.reactivestreams.Publisher;
|
import org.reactivestreams.Publisher;
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
import org.springframework.cloud.function.context.FunctionRegistration;
|
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.core.ResolvableType;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
@@ -223,6 +228,33 @@ public final class FunctionTypeUtils {
|
|||||||
return inputType;
|
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")
|
@SuppressWarnings("unchecked")
|
||||||
public static Type getOutputType(Type functionType) {
|
public static Type getOutputType(Type functionType) {
|
||||||
assertSupportedTypes(functionType);
|
assertSupportedTypes(functionType);
|
||||||
@@ -291,34 +323,11 @@ public final class FunctionTypeUtils {
|
|||||||
return isOfType(type, Consumer.class);
|
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) {
|
public static boolean isMono(Type type) {
|
||||||
type = extractReactiveType(type);
|
type = extractReactiveType(type);
|
||||||
return type == null ? false : type.getTypeName().startsWith("reactor.core.publisher.Mono");
|
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) {
|
public static boolean isMultipleArgumentType(Type type) {
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
if (TypeResolver.resolveRawClass(type, null).isArray()) {
|
if (TypeResolver.resolveRawClass(type, null).isArray()) {
|
||||||
@@ -350,12 +359,6 @@ public final class FunctionTypeUtils {
|
|||||||
ResolvableType.forMethodReturnType(functionalMethod)).getType();
|
ResolvableType.forMethodReturnType(functionalMethod)).getType();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// case 2:
|
|
||||||
// ResolvableType canonicalParametersWrapper = fromTwoArityFunction(functionalMethod);
|
|
||||||
// functionType = ResolvableType.forClassWithGenerics(Function.class,
|
|
||||||
// canonicalParametersWrapper,
|
|
||||||
// ResolvableType.forMethodReturnType(functionalMethod)).getType();
|
|
||||||
// break;
|
|
||||||
default:
|
default:
|
||||||
throw new UnsupportedOperationException("Functional method: " + functionalMethod + " is not supported");
|
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");
|
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) {
|
private static void assertSupportedTypes(Type type) {
|
||||||
if (type instanceof ParameterizedType) {
|
if (type instanceof ParameterizedType) {
|
||||||
type = ((ParameterizedType) type).getRawType();
|
type = ((ParameterizedType) type).getRawType();
|
||||||
@@ -392,4 +405,29 @@ public final class FunctionTypeUtils {
|
|||||||
}
|
}
|
||||||
return type;
|
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