diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistry.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistry.java index 3cc761417..5cee940aa 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistry.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/BeanFactoryAwareFunctionRegistry.java @@ -123,6 +123,7 @@ public class BeanFactoryAwareFunctionRegistry @SuppressWarnings({ "rawtypes", "unchecked" }) @Override + //TODO do we really need to do that given we no longer do the same for other gunctions? public void afterSingletonsInstantiated() { Map beansOfType = this.applicationContext .getBeansOfType(FunctionRegistration.class); @@ -190,7 +191,9 @@ public class BeanFactoryAwareFunctionRegistry else { if (StringUtils.isEmpty(definition)) { String[] functionNames = this.applicationContext.getBeanNamesForType(Function.class); - Assert.notEmpty(functionNames, "Can't find any functions in BeanFactory"); + if (ObjectUtils.isEmpty(functionNames)) { + return null; + } Assert.isTrue(functionNames.length == 1, "Found more then one function in BeanFactory"); definition = functionNames[0]; } @@ -349,12 +352,6 @@ public class BeanFactoryAwareFunctionRegistry return target; } -// public boolean isMultipleOutput() { -// -// Type type = FunctionTypeUtils.getInputType(functionType, 0); -// return FunctionTypeUtils.isFlux(type); -// } - @SuppressWarnings({ "rawtypes", "unchecked" }) private Object invokeFunction(Object input) { if (target instanceof FunctionInvocationWrapper || target instanceof Function) { @@ -482,7 +479,7 @@ public class BeanFactoryAwareFunctionRegistry } private Publisher convertOutputPublisherIfNecessary(Publisher publisher, String... acceptedOutputMimeTypes) { - System.out.println("Converting output publisher"); + logger.info("Applying type conversion on output Publisher"); Publisher result = publisher instanceof Mono ? Mono.from(publisher).map(value -> this.convertOutputValueIfNecessary(value, acceptedOutputMimeTypes)) : Flux.from(publisher).map(value -> this.convertOutputValueIfNecessary(value, acceptedOutputMimeTypes)); @@ -490,7 +487,7 @@ public class BeanFactoryAwareFunctionRegistry } private Publisher convertInputPublisherIfNecessary(Publisher publisher, Type type) { - System.out.println("Converting publisher"); + logger.info("Applying type conversion on input Publisher"); Publisher result = publisher instanceof Mono ? Mono.from(publisher).map(value -> this.convertInputValueIfNecessary(value, type)) : Flux.from(publisher).map(value -> this.convertInputValueIfNecessary(value, type)); @@ -498,7 +495,7 @@ public class BeanFactoryAwareFunctionRegistry } private Object convertInputValueIfNecessary(Object value, Type type) { - System.out.println("Converting value"); + logger.info("Applying type conversion on actual value "); Object convertedValue = value; if (FunctionTypeUtils.isMultipleArgumentsHolder(value)) { int inputCount = FunctionTypeUtils.getInputCount(functionType); @@ -516,12 +513,12 @@ public class BeanFactoryAwareFunctionRegistry else { // this needs revisiting as the type is not always Class (think really complex types) Type rawType = FunctionTypeUtils.unwrapActualTypeByIndex(type, 0); - if (/*!(rawType instanceof Class) && */rawType instanceof ParameterizedType) { + if (rawType instanceof ParameterizedType) { rawType = ((ParameterizedType) rawType).getRawType(); } if (value instanceof Message) { // see AWS adapter with Optional payload if (messageNeedsConversion(rawType, (Message) value)) { - convertedValue = messageConverter.fromMessage((Message) value, (Class) rawType, type); + convertedValue = messageConverter.fromMessage((Message) value, (Class) rawType); if (FunctionTypeUtils.isMessage(type)) { convertedValue = MessageBuilder.withPayload(convertedValue).copyHeaders(((Message) value).getHeaders()).build(); } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java index 69c151e60..6d3487b6d 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionTypeUtils.java @@ -35,16 +35,20 @@ import org.springframework.util.ObjectUtils; * @author Oleg Zhurakousky * @since 3.0 */ -final class FunctionTypeUtils { +public final class FunctionTypeUtils { private FunctionTypeUtils() { } - /** - * Will extract the relevant type (e.g., for type conversion purposes). Useful to extract - * types wrapped in Publisher and/or Message. - */ + public static Type getFunctionType(Object function, FunctionInspector inspector) { + FunctionRegistration registration = inspector.getRegistration(function); + if (registration != null) { + return registration.getType().getType(); + } + return null; + } + public static Type unwrapActualTypeByIndex(Type type, int index) { if (isMessage(type) || isPublisher(type)) { if (isPublisher(type)) { @@ -144,10 +148,9 @@ final class FunctionTypeUtils { public static boolean isReactive(Type type) { - if (type instanceof ParameterizedType) { - return Publisher.class.isAssignableFrom(((Class) ((ParameterizedType) type).getRawType())); - } - return false; + Class rawType = type instanceof ParameterizedType + ? (Class) ((ParameterizedType) type).getRawType() : (type instanceof Class ? (Class) type : Object.class); + return Publisher.class.isAssignableFrom(rawType); } public static boolean isConsumer(Type type) { diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfiguration.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfiguration.java index 32dc214d2..13c4588a0 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfiguration.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfiguration.java @@ -90,15 +90,10 @@ public class ContextFunctionCatalogAutoConfiguration { static final String PREFERRED_MAPPER_PROPERTY = "spring.http.converters.preferred-json-mapper"; -// @Bean - public FunctionRegistry functionCatalog() { - return new BeanFactoryFunctionCatalog(); - } - @Bean - public FunctionRegistry functionCatalog(@Nullable ConversionService conversionService, @Nullable CompositeMessageConverter messageConverter, + public FunctionRegistry functionCatalog(@Nullable CompositeMessageConverter messageConverter, Map additionalConverters) { - conversionService = conversionService == null ? new DefaultConversionService() : conversionService; + ConversionService conversionService = new DefaultConversionService(); if (messageConverter == null) { List messageConverters = new ArrayList<>(); messageConverters.addAll(additionalConverters.values()); @@ -107,6 +102,7 @@ public class ContextFunctionCatalogAutoConfiguration { messageConverters.add(new StringMessageConverter()); messageConverter = new CompositeMessageConverter(messageConverters); } + return new BeanFactoryAwareFunctionRegistry(conversionService, messageConverter); }