diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionCatalog.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionCatalog.java index c15706715..1b11d9115 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionCatalog.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionCatalog.java @@ -17,9 +17,17 @@ package org.springframework.cloud.function.context; import java.util.Set; +import java.util.function.Function; +import org.springframework.messaging.Message; +import org.springframework.messaging.converter.MessageConverter; import org.springframework.util.MimeType; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.util.function.Tuple2; +import reactor.util.function.Tuple3; + /** * @author Dave Syer @@ -29,42 +37,70 @@ public interface FunctionCatalog { - default T lookup(String name, MimeType... acceptedOutputTypes) { - throw new UnsupportedOperationException( - "This instance of FunctionCatalog does not support this operation"); - } + /** + * Will look up the instance of the functional interface. The 'acceptedOutputTypes' + * will be used by the available {@link MessageConverter}s to convert the values of output streams. + * This means that regardless of the actual function signature the return types of the function + * will always be {@link Message}. + *
+ * For example, + *
+ * Assume user function is: + *
+ * {@code + * Function, Tuple2>, Mono>> + * } + *
+ * While you can provide input of any type (the internal conversion routing will kick in), + * the output type will always be assumed as Message where 'T' is the type returned by + * the corresponding {@link MessageConverter#toMessage(Object, org.springframework.messaging.MessageHeaders)} + * method. For example, providing that the existing {@link MessageConverter}s convert to Message, the + * above user function could be invoked as: + *
+ * {@code + * Function, Tuple2>, Mono>>> + * } + * @param functionDefinition the definition of the functional interface. Must not be null; + * @param acceptedOutputTypes ordered array of accepted mime types to be used to + * generate output streams. The size of the array must match the count of function output. + * @return instance of the functional interface registered with this catalog + */ + default T lookup(String functionDefinition, MimeType... acceptedOutputTypes) { + throw new UnsupportedOperationException( + "This instance of FunctionCatalog does not support this operation"); + } - /** - * Will look up the instance of the functional interface by name only. - * @param instance type - * @param name the name of the functional interface. Must not be null; - * @return instance of the functional interface registered with this catalog - */ - default T lookup(String name) { - return this.lookup(null, name); - } + /** + * Will look up the instance of the functional interface by name only. + * @param instance type + * @param functionDefinition the definition of the functional interface. Must not be null; + * @return instance of the functional interface registered with this catalog + */ + default T lookup(String functionDefinition) { + return this.lookup(null, functionDefinition); + } - /** - * Will look up the instance of the functional interface by name and type which can - * only be Supplier, Consumer or Function. If type is not provided, the lookup will be - * made based on name only. - * @param instance type - * @param type the type of functional interface. Can be null - * @param name the name of the functional interface. Must not be null; - * @return instance of the functional interface registered with this catalog - */ - T lookup(Class type, String name); + /** + * Will look up the instance of the functional interface by name and type which can + * only be Supplier, Consumer or Function. If type is not provided, the lookup will be + * made based on name only. + * @param instance type + * @param type the type of functional interface. Can be null + * @param functionDefinition the definition of the functional interface. Must not be null; + * @return instance of the functional interface registered with this catalog + */ + T lookup(Class type, String functionDefinition); - Set getNames(Class type); + Set getNames(Class type); - /** - * Return the count of functions registered in this catalog. - * @return the count of functions registered in this catalog - */ - default int size() { - throw new UnsupportedOperationException( - "This instance of FunctionCatalog does not support this operation"); - } + /** + * Return the count of functions registered in this catalog. + * @return the count of functions registered in this catalog + */ + default int size() { + throw new UnsupportedOperationException( + "This instance of FunctionCatalog does not support this operation"); + } } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/LazyFunctionRegistry.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/LazyFunctionRegistry.java index 5c664fece..076c3d922 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/LazyFunctionRegistry.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/LazyFunctionRegistry.java @@ -42,6 +42,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.convert.ConversionService; import org.springframework.lang.Nullable; import org.springframework.messaging.converter.CompositeMessageConverter; +import org.springframework.util.Assert; import org.springframework.util.MimeType; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; @@ -83,6 +84,7 @@ public class LazyFunctionRegistry implements FunctionRegistry, FunctionInspector @SuppressWarnings("unchecked") public T lookup(String definition, MimeType... acceptedOutputTypes) { + Assert.notEmpty(acceptedOutputTypes, "'acceptedOutputTypes' must not be null or empty"); return (T) this.compose(null, definition, acceptedOutputTypes); }