Add function type discovery method to FunctionTypeUtils

This commit is contained in:
Oleg Zhurakousky
2020-10-22 09:58:34 +02:00
parent 222aac77cc
commit b61e357144
2 changed files with 75 additions and 75 deletions

View File

@@ -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)

View File

@@ -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);
}
}