From 818cda144cd69e21b3a040d2c40cbc56f0b393b4 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Mon, 19 Oct 2020 15:30:11 +0200 Subject: [PATCH] Deprecate and remove all usages of FunctionInspector --- .../aws/SpringBootKinesisEventHandler.java | 1 + .../azure/AzureSpringBootRequestHandler.java | 8 +- ...tractSpringFunctionAdapterInitializer.java | 17 +- .../context/catalog/FunctionInspector.java | 30 +- .../context/catalog/FunctionTypeUtils.java | 81 +++-- .../catalog/SimpleFunctionRegistry.java | 6 +- ...FunctionCatalogAutoConfigurationTests.java | 339 ++++++------------ .../function/web/BasicStringConverter.java | 12 +- .../cloud/function/web/RequestProcessor.java | 48 ++- .../web/flux/ReactorAutoConfiguration.java | 8 +- .../function/FunctionEndpointInitializer.java | 29 +- .../web/mvc/ReactorAutoConfiguration.java | 8 +- 12 files changed, 268 insertions(+), 319 deletions(-) diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootKinesisEventHandler.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootKinesisEventHandler.java index 161e95f8b..506d7e03b 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootKinesisEventHandler.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootKinesisEventHandler.java @@ -32,6 +32,7 @@ import org.springframework.messaging.support.GenericMessage; import static java.util.stream.Collectors.toList; + /** * @param payload type * @param response type diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandler.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandler.java index b1918d09e..e3c96ef02 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandler.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandler.java @@ -27,6 +27,8 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import org.springframework.cloud.function.context.AbstractSpringFunctionAdapterInitializer; +import org.springframework.cloud.function.context.catalog.FunctionTypeUtils; +import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; /** * @param input type @@ -129,7 +131,7 @@ public class AzureSpringBootRequestHandler extends AbstractSpringFunctionA } if (getInspector() != null) { return Collection.class - .isAssignableFrom(getInspector().getInputType(function)); + .isAssignableFrom(((FunctionInvocationWrapper) function).getRawInputType()); } return ((Collection) input).size() <= 1; } @@ -139,8 +141,8 @@ public class AzureSpringBootRequestHandler extends AbstractSpringFunctionA return true; } if (getInspector() != null) { - return Collection.class - .isAssignableFrom(getInspector().getOutputType(function)); + Class outputType = FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(((FunctionInvocationWrapper) function).getOutputType())); + return Collection.class.isAssignableFrom(outputType); } return ((Collection) output).size() <= 1; } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/AbstractSpringFunctionAdapterInitializer.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/AbstractSpringFunctionAdapterInitializer.java index bbb7efb26..04115842f 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/AbstractSpringFunctionAdapterInitializer.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/AbstractSpringFunctionAdapterInitializer.java @@ -36,6 +36,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; import org.springframework.cloud.function.context.catalog.FunctionInspector; +import org.springframework.cloud.function.context.catalog.FunctionTypeUtils; +import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; import org.springframework.cloud.function.context.config.FunctionContextUtils; import org.springframework.cloud.function.context.config.RoutingFunction; import org.springframework.cloud.function.json.JsonMapper; @@ -138,15 +140,18 @@ public abstract class AbstractSpringFunctionAdapterInitializer implements Clo } } + @Deprecated protected FunctionInspector getInspector() { return inspector; } protected Class getInputType() { - if (this.inspector != null) { - return this.inspector.getInputType(function()); + + Object func = function(); + if (func != null && func instanceof FunctionInvocationWrapper) { + return FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(((FunctionInvocationWrapper) func).getInputType())); } - else if (functionRegistration != null) { + if (functionRegistration != null) { return functionRegistration.getType().getInputType(); } return Object.class; @@ -237,7 +242,7 @@ public abstract class AbstractSpringFunctionAdapterInitializer implements Clo } if (getInspector() != null) { return Collection.class - .isAssignableFrom(getInspector().getInputType(function)); + .isAssignableFrom(((FunctionInvocationWrapper) function).getRawInputType()); } return ((Collection) input).size() <= 1; } @@ -247,8 +252,8 @@ public abstract class AbstractSpringFunctionAdapterInitializer implements Clo return true; } if (getInspector() != null) { - return Collection.class - .isAssignableFrom(getInspector().getOutputType(function)); + Class outputType = FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(((FunctionInvocationWrapper) function).getOutputType())); + return Collection.class.isAssignableFrom(outputType); } return ((Collection) output).size() <= 1; } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionInspector.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionInspector.java index a6f72922c..0b23146b0 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionInspector.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionInspector.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,7 +31,10 @@ import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry /** * @author Dave Syer * @author Oleg Zhurakousky + * + * @deprecated since 3.1 no longer used by the framework */ +@Deprecated public interface FunctionInspector { FunctionRegistration getRegistration(Object function); @@ -49,6 +52,11 @@ public interface FunctionInspector { return ((FunctionInvocationWrapper) function).isInputTypeMessage(); } + /** + * + * @deprecated since 3.1 no longer used by the framework + */ + @Deprecated default Class getInputType(Object function) { if (function == null) { return Object.class; @@ -69,6 +77,11 @@ public interface FunctionInspector { return inputType; } + /** + * + * @deprecated since 3.1 no longer used by the framework + */ + @Deprecated default Class getOutputType(Object function) { if (function == null) { return Object.class; @@ -89,6 +102,11 @@ public interface FunctionInspector { return outputType; } + /** + * + * @deprecated since 3.1 no longer used by the framework + */ + @Deprecated default Class getInputWrapper(Object function) { Class c = function == null ? Object.class : TypeResolver.resolveRawClass(((FunctionInvocationWrapper) function).getInputType(), null); if (Flux.class.isAssignableFrom(c)) { @@ -102,6 +120,11 @@ public interface FunctionInspector { } } + /** + * + * @deprecated since 3.1 no longer used by the framework + */ + @Deprecated default Class getOutputWrapper(Object function) { Class c = function == null ? Object.class : TypeResolver.resolveRawClass(((FunctionInvocationWrapper) function).getOutputType(), null); if (Flux.class.isAssignableFrom(c)) { @@ -115,6 +138,11 @@ public interface FunctionInspector { } } + /** + * + * @deprecated since 3.1 no longer used by the framework + */ + @Deprecated default String getName(Object function) { if (function == null) { return null; 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 b0ae74874..30e079e4f 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 @@ -1,5 +1,5 @@ /* - * Copyright 2019-2019 the original author or authors. + * Copyright 2019-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,8 @@ import java.util.function.Supplier; import java.util.stream.Stream; import net.jodah.typetools.TypeResolver; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; @@ -50,6 +52,8 @@ import org.springframework.util.ReflectionUtils; */ public final class FunctionTypeUtils { + private static Log logger = LogFactory.getLog(FunctionTypeUtils.class); + private FunctionTypeUtils() { } @@ -86,6 +90,10 @@ public final class FunctionTypeUtils { return type; } + public static Class getRawType(Type type) { + return type != null ? TypeResolver.resolveRawClass(type, null) : null; + } + /** * Will attempt to discover functional methods on the class. It's applicable for POJOs as well as * functional classes in `java.util.function` package. For the later the names of the methods are @@ -188,41 +196,52 @@ public final class FunctionTypeUtils { return outputCount; } + /** + * Returns input type of function type that represents Function or Consumer. + * @param functionType the Type of Function or Consumer + * @return the input type as {@link Type} + */ @SuppressWarnings("unchecked") public static Type getInputType(Type functionType) { + if (isSupplier(functionType)) { + logger.debug("Supplier does not have input type, returning null as input type."); + return null; + } assertSupportedTypes(functionType); + + Type inputType; if (functionType instanceof Class) { - Class functionClass = (Class) functionType; - if (Function.class.isAssignableFrom(functionClass)) { - functionType = TypeResolver.reify(Function.class, (Class>) functionClass); - } - else if (Consumer.class.isAssignableFrom(functionClass)) { - functionType = TypeResolver.reify(Consumer.class, (Class>) functionClass); - } - else { - return null; - } + functionType = Function.class.isAssignableFrom((Class) functionType) + ? TypeResolver.reify(Function.class, (Class>) functionType) + : TypeResolver.reify(Consumer.class, (Class>) functionType); } - Type inputType = Object.class; - if ((isFunction(functionType) || isConsumer(functionType)) && functionType instanceof ParameterizedType) { - inputType = ((ParameterizedType) functionType).getActualTypeArguments()[0]; - } + inputType = functionType instanceof ParameterizedType + ? ((ParameterizedType) functionType).getActualTypeArguments()[0] + : Object.class; return inputType; } - public static Type getOutputType(Type functionType, int index) { + @SuppressWarnings("unchecked") + public static Type getOutputType(Type functionType) { assertSupportedTypes(functionType); - if (isFunction(functionType)) { - return functionType instanceof ParameterizedType ? ((ParameterizedType) functionType).getActualTypeArguments()[1] : Object.class; - } - else if (isSupplier(functionType)) { - return functionType instanceof ParameterizedType ? ((ParameterizedType) functionType).getActualTypeArguments()[0] : Object.class; - } - else { + if (isConsumer(functionType)) { + logger.debug("Consumer does not have output type, returning null as output type."); return null; } + Type inputType; + if (functionType instanceof Class) { + functionType = Function.class.isAssignableFrom((Class) functionType) + ? TypeResolver.reify(Function.class, (Class>) functionType) + : TypeResolver.reify(Function.class, (Class>) functionType); + } + + inputType = functionType instanceof ParameterizedType + ? (isSupplier(functionType) ? ((ParameterizedType) functionType).getActualTypeArguments()[0] : ((ParameterizedType) functionType).getActualTypeArguments()[1]) + : Object.class; + + return inputType; } public static Type getImmediateGenericType(Type type, int index) { @@ -238,8 +257,6 @@ public final class FunctionTypeUtils { public static boolean isFlux(Type type) { return TypeResolver.resolveRawClass(type, null) == Flux.class; -// type = extractReactiveType(type); -// return type.getTypeName().startsWith("reactor.core.publisher.Flux"); } public static boolean isMessage(Type type) { @@ -252,23 +269,13 @@ public final class FunctionTypeUtils { return TypeResolver.resolveRawClass(type, null) == Message.class; } - /** - * Determines if input argument to a Function is an array. - * @param functionType the function type - * @return true if input type is an array, otherwise false - */ - public static boolean isInputArray(Type functionType) { - Type inputType = FunctionTypeUtils.getInputType(functionType); - return inputType instanceof GenericArrayType || inputType instanceof Class && ((Class) inputType).isArray(); - } - /** * Determines if input argument to a Function is an array. * @param functionType the function type * @return true if input type is an array, otherwise false */ public static boolean isOutputArray(Type functionType) { - Type outputType = FunctionTypeUtils.getOutputType(functionType, 0); + Type outputType = FunctionTypeUtils.getOutputType(functionType); return outputType instanceof GenericArrayType || outputType instanceof Class && ((Class) outputType).isArray(); } @@ -296,7 +303,7 @@ public final class FunctionTypeUtils { public static boolean isMono(Type type) { type = extractReactiveType(type); - return type.getTypeName().startsWith("reactor.core.publisher.Mono"); + return type == null ? false : type.getTypeName().startsWith("reactor.core.publisher.Mono"); } private static boolean isFunctional(Type type) { diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistry.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistry.java index 9f02ca2c3..4979aec08 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistry.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistry.java @@ -250,7 +250,7 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect private FunctionInvocationWrapper invocationWrapperInstance(String functionDefinition, Object target, Type functionType) { return invocationWrapperInstance(functionDefinition, target, FunctionTypeUtils.isSupplier(functionType) ? null : FunctionTypeUtils.getInputType(functionType), - FunctionTypeUtils.getOutputType(functionType, 0)); + FunctionTypeUtils.getOutputType(functionType)); } /** @@ -325,11 +325,11 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect } public Class getRawOutputType() { - return TypeResolver.resolveRawClass(this.outputType, null); + return this.outputType == null ? null : TypeResolver.resolveRawClass(this.outputType, null); } public Class getRawInputType() { - return TypeResolver.resolveRawClass(this.inputType, null); + return this.inputType == null ? null : TypeResolver.resolveRawClass(this.inputType, null); } /** diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfigurationTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfigurationTests.java index 406148c0c..4e9163e67 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfigurationTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.springframework.cloud.function.context.config; +import java.lang.reflect.Type; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; @@ -47,7 +48,7 @@ import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.function.context.FunctionCatalog; import org.springframework.cloud.function.context.FunctionRegistration; import org.springframework.cloud.function.context.FunctionRegistry; -import org.springframework.cloud.function.context.catalog.FunctionInspector; +import org.springframework.cloud.function.context.catalog.FunctionTypeUtils; import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; import org.springframework.cloud.function.inject.FooConfiguration; import org.springframework.cloud.function.scan.ScannedFunction; @@ -77,24 +78,15 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class ContextFunctionCatalogAutoConfigurationTests { - private static String value; - private ConfigurableApplicationContext context; private FunctionCatalog catalog; - private FunctionInspector inspector; - - public static void set(Object value) { - ContextFunctionCatalogAutoConfigurationTests.value = value.toString(); - } - @AfterEach public void close() { if (this.context != null) { this.context.close(); } - ContextFunctionCatalogAutoConfigurationTests.value = null; } @Test @@ -112,11 +104,9 @@ public class ContextFunctionCatalogAutoConfigurationTests { assertThat(f.apply(Flux.just("hello")).blockFirst()) .isEqualTo("HELLOfunction2function3"); assertThat(this.context.getBean("supplierFoo")).isInstanceOf(Supplier.class); -// assertThat((Supplier) this.catalog.lookup(Supplier.class, "supplierFoo")) -// .isInstanceOf(Supplier.class); -// assertThat(this.context.getBean("supplier_Foo")).isInstanceOf(Supplier.class); -// assertThat((Supplier) this.catalog.lookup(Supplier.class, "supplier_Foo")) -// .isInstanceOf(Supplier.class); + assertThat((Supplier) this.catalog.lookup(Supplier.class, "supplierFoo")) + .isInstanceOf(Supplier.class); + assertThat(this.context.getBean("supplier_Foo")).isInstanceOf(Supplier.class); } @Test @@ -128,29 +118,23 @@ public class ContextFunctionCatalogAutoConfigurationTests { .isInstanceOf(Function.class); assertThat((Supplier) this.catalog.lookup(Supplier.class, "foos")) .isInstanceOf(Supplier.class); - assertThat( - this.inspector.getInputType(this.catalog.lookup(Function.class, "foos"))) - .isEqualTo(String.class); - assertThat( - this.inspector.getOutputType(this.catalog.lookup(Supplier.class, "foos"))) - .isEqualTo(Foo.class); + Class inputType = ((FunctionInvocationWrapper) this.catalog.lookup(Function.class, "foos")).getRawInputType(); + assertThat(inputType).isEqualTo(String.class); + FunctionInvocationWrapper function = this.catalog.lookup("foos"); + Type outputType = function.getOutputType(); + assertThat((Class) FunctionTypeUtils.getGenericType(outputType)).isEqualTo(Foo.class); } @Test public void configurationFunction() { create(FunctionConfiguration.class); assertThat(this.context.getBean("foos")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "foos")) - .isInstanceOf(Function.class); - assertThat( - this.inspector.getInputType(this.catalog.lookup(Function.class, "foos"))) - .isEqualTo(String.class); - assertThat( - this.inspector.getOutputType(this.catalog.lookup(Function.class, "foos"))) - .isEqualTo(Foo.class); - assertThat(this.inspector - .getInputWrapper(this.catalog.lookup(Function.class, "foos"))) - .isEqualTo(Flux.class); + FunctionInvocationWrapper function = this.catalog.lookup(Function.class, "foos"); + assertThat(function).isInstanceOf(Function.class); + Type inputType = function.getInputType(); + assertThat(FunctionTypeUtils.getGenericType(inputType)).isEqualTo(String.class); + Type outputType = function.getOutputType(); + assertThat((Class) FunctionTypeUtils.getGenericType(outputType)).isEqualTo(Foo.class); } @Test @@ -159,9 +143,8 @@ public class ContextFunctionCatalogAutoConfigurationTests { assertThat(this.context.getBean("foos")).isInstanceOf(Function.class); assertThat((Function) this.catalog.lookup(Function.class, "foos")) .isInstanceOf(Function.class); -// assertThat( -// this.inspector.getInputType(this.catalog.lookup(Function.class, "foos"))) -// .isEqualTo(String.class); + Class inputType = ((FunctionInvocationWrapper) this.catalog.lookup(Function.class, "foos")).getRawInputType(); + assertThat(inputType).isEqualTo(String.class); } @Test @@ -170,200 +153,145 @@ public class ContextFunctionCatalogAutoConfigurationTests { assertThat(this.context.getBean("foos")).isInstanceOf(Function.class); assertThat((Function) this.catalog.lookup(Function.class, "foos")) .isInstanceOf(Function.class); -// assertThat( -// this.inspector.getInputType(this.catalog.lookup(Function.class, "foos"))) -// .isEqualTo(String.class); + Class inputType = ((FunctionInvocationWrapper) this.catalog.lookup(Function.class, "foos")).getRawInputType(); + assertThat(inputType).isEqualTo(String.class); } @Test public void composedFunction() { create(MultipleConfiguration.class); - assertThat((Function) this.catalog.lookup(Function.class, "foos,bars")) - .isInstanceOf(Function.class); -// assertThat((Function) this.catalog.lookup(Function.class, "names,foos")) -// .isNull(); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "foos,bars"))) -// .isAssignableFrom(String.class); -// assertThat(this.inspector -// .getOutputType(this.catalog.lookup(Function.class, "foos,bars"))) -// .isAssignableFrom(Bar.class); + FunctionInvocationWrapper function = this.catalog.lookup(Function.class, "foos"); + assertThat(function).isInstanceOf(Function.class); + + function = this.catalog.lookup(Function.class, "foos,bars"); + Class inputType = function.getRawInputType(); + assertThat(inputType).isAssignableFrom(String.class); + Class outputType = function.getRawOutputType(); + assertThat(outputType).isAssignableFrom(Bar.class); } @Test public void composedSupplier() { create(MultipleConfiguration.class); - assertThat((Supplier) this.catalog.lookup(Supplier.class, "names,foos")) - .isInstanceOf(Supplier.class); -// assertThat((Function) this.catalog.lookup(Function.class, "names,foos")) -// .isNull(); -// assertThat(this.inspector -// .getOutputType(this.catalog.lookup(Supplier.class, "names,foos"))) -// .isAssignableFrom(Foo.class); - // The input type is the same as the input type of the first element in the chain -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Supplier.class, "names,foos"))) -// .isAssignableFrom(Void.class); + FunctionInvocationWrapper function = this.catalog.lookup("names,foos"); + assertThat(function).isInstanceOf(Supplier.class); + assertThat(function.getRawOutputType()).isAssignableFrom(Foo.class); + assertThat(function.getRawInputType()).isNull(); } @Test public void composedConsumer() { create(MultipleConfiguration.class); - assertThat((Consumer) this.catalog.lookup(Consumer.class, "foos,print")) - .isInstanceOf(Consumer.class); -// .isNull(); - assertThat((Function) this.catalog.lookup(Function.class, "foos,print")) - .isInstanceOf(Function.class); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "foos,print"))) -// .isAssignableFrom(String.class); -// // The output type is the same as the output type of the last element in the chain -// assertThat(this.inspector -// .getOutputType(this.catalog.lookup(Function.class, "foos,print"))) -// .isAssignableFrom(Void.class); + FunctionInvocationWrapper function = this.catalog.lookup("foos,print"); + assertThat(function).isInstanceOf(Consumer.class); + assertThat(function).isInstanceOf(Function.class); + assertThat(function.getRawInputType()).isAssignableFrom(String.class); + assertThat(function.getRawOutputType()).isNull(); } @Test public void genericFunction() { create(GenericConfiguration.class); + FunctionInvocationWrapper function = this.catalog.lookup("function"); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Map.class); -// assertThat(this.inspector -// .getInputWrapper(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Map.class); + assertThat(function).isInstanceOf(Function.class); + assertThat(function.getRawInputType()).isAssignableFrom(Map.class); } @Test public void fluxMessageFunction() { create(FluxMessageConfiguration.class); + FunctionInvocationWrapper function = this.catalog.lookup("function"); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); -// assertThat( -// this.inspector.isMessage(this.catalog.lookup(Function.class, "function"))) -// .isTrue(); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(String.class); -// assertThat(this.inspector -// .getInputWrapper(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Flux.class); + assertThat(function).isInstanceOf(Function.class); + assertThat(function.isInputTypeMessage()).isTrue(); + + Type inputType = function.getInputType(); + + assertThat((Class) FunctionTypeUtils.getGenericType(inputType)).isAssignableFrom(String.class); } @Test public void publisherMessageFunction() { create(PublisherMessageConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); -// assertThat( -// this.inspector.isMessage(this.catalog.lookup(Function.class, "function"))) -// .isTrue(); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(String.class); -// assertThat(this.inspector -// .getInputWrapper(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Publisher.class); + FunctionInvocationWrapper function = this.catalog.lookup("function"); + assertThat(function).isInstanceOf(Function.class); + assertThat(function.isInputTypeMessage()).isTrue(); + + Type inputType = function.getInputType(); + assertThat((Class) FunctionTypeUtils.getGenericType(inputType)).isAssignableFrom(String.class); + assertThat(FunctionTypeUtils.getRawType(inputType)).isAssignableFrom(Publisher.class); } @Test public void monoFunction() { create(MonoConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); -// assertThat( -// this.inspector.isMessage(this.catalog.lookup(Function.class, "function"))) -// .isFalse(); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(String.class); -// assertThat(this.inspector -// .getInputWrapper(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Flux.class); -// assertThat(this.inspector -// .getOutputWrapper(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Mono.class); + FunctionInvocationWrapper function = this.catalog.lookup("function"); + assertThat(function).isInstanceOf(Function.class); + assertThat(function.isInputTypeMessage()).isFalse(); + Type inputType = function.getInputType(); + Type outputType = function.getOutputType(); + assertThat((Class) FunctionTypeUtils.getGenericType(inputType)).isAssignableFrom(String.class); + assertThat(FunctionTypeUtils.getRawType(inputType)).isAssignableFrom(Flux.class); + assertThat(FunctionTypeUtils.getRawType(outputType)).isAssignableFrom(Mono.class); } - @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void monoToMonoNonVoidFunction() { create(MonoToMonoNonVoidConfiguration.class); - assertThat(this.context.getBean("function")).isInstanceOf(Function.class); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(String.class); -// assertThat(this.inspector -// .getOutputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(String.class); - - Function function = this.context.getBean(FunctionCatalog.class).lookup("function"); - Object result = ((Mono) function.apply(Mono.just("flux"))).block(); + FunctionInvocationWrapper function = this.catalog.lookup("function"); + assertThat(function).isInstanceOf(Function.class); + Type inputType = function.getInputType(); + assertThat((Class) FunctionTypeUtils.getGenericType(inputType)).isAssignableFrom(String.class); + Type outputType = function.getOutputType(); + assertThat((Class) FunctionTypeUtils.getGenericType(outputType)).isAssignableFrom(String.class); } @Test public void messageFunction() { create(MessageConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); -// assertThat( -// this.inspector.isMessage(this.catalog.lookup(Function.class, "function"))) -// .isTrue(); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(String.class); -// assertThat(this.inspector -// .getInputWrapper(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(String.class); + FunctionInvocationWrapper function = this.catalog.lookup("function"); + assertThat(function).isInstanceOf(Function.class); + assertThat(function.isInputTypeMessage()).isTrue(); + assertThat(function.isOutputTypeMessage()).isTrue(); + Type inputType = function.getInputType(); + assertThat((Class) FunctionTypeUtils.getGenericType(inputType)).isAssignableFrom(String.class); } @Test public void genericFluxFunction() { create(GenericFluxConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Map.class); -// assertThat(this.inspector -// .getInputWrapper(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Flux.class); + FunctionInvocationWrapper function = this.catalog.lookup("function"); + assertThat(function).isInstanceOf(Function.class); + Type inputType = function.getInputType(); + assertThat(FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(inputType))).isAssignableFrom(Map.class); + assertThat(FunctionTypeUtils.getRawType(inputType)).isAssignableFrom(Flux.class); } @Test public void externalFunction() { create(ExternalConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Map.class); -// assertThat(this.inspector -// .getInputWrapper(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Map.class); + FunctionInvocationWrapper function = this.catalog.lookup("function"); + assertThat(function).isInstanceOf(Function.class); + Type inputType = function.getInputType(); + assertThat(FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(inputType))).isAssignableFrom(Map.class); } @Test public void singletonFunction() { create(SingletonConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Integer.class); -// assertThat(this.inspector -// .getInputWrapper(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Integer.class); + FunctionInvocationWrapper function = this.catalog.lookup("function"); + assertThat(function).isInstanceOf(Function.class); + assertThat(function.isInputTypePublisher()).isFalse(); + assertThat(function.isOutputTypePublisher()).isFalse(); + Type inputType = function.getInputType(); + assertThat(FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(inputType))).isAssignableFrom(Integer.class); } @Test @@ -371,58 +299,41 @@ public class ContextFunctionCatalogAutoConfigurationTests { public void singletonMessageFunction() { create(SingletonMessageConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); - assertThat(this.inspector - .getInputType(this.catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Integer.class); - assertThat(this.inspector - .getInputWrapper(this.catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Integer.class); - assertThat(((FunctionInvocationWrapper) this.catalog.lookup(Function.class, "function")).isInputTypeMessage()) - .isTrue(); + FunctionInvocationWrapper function = this.catalog.lookup("function"); + assertThat(function).isInstanceOf(Function.class); + assertThat(function.isInputTypeMessage()).isTrue(); + Type inputType = function.getInputType(); + assertThat((Class) FunctionTypeUtils.getGenericType(inputType)).isAssignableFrom(Integer.class); } @Test public void nonParametericTypeFunction() { create(NonParametricTypeSingletonConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Integer.class); -// assertThat(this.inspector -// .getInputWrapper(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Integer.class); + FunctionInvocationWrapper function = this.catalog.lookup("function"); + assertThat(function).isInstanceOf(Function.class); + Type inputType = function.getInputType(); + assertThat((Class) FunctionTypeUtils.getGenericType(inputType)).isAssignableFrom(Integer.class); } @Test public void componentScanBeanFunction() { create(ComponentScanBeanConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Map.class); -// assertThat(this.inspector -// .getInputWrapper(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Map.class); + FunctionInvocationWrapper function = this.catalog.lookup("function"); + assertThat(function).isInstanceOf(Function.class); + Type inputType = function.getInputType(); + assertThat(FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(inputType))).isAssignableFrom(Map.class); } @Test public void componentScanFunction() { create(ComponentScanConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Map.class); -// assertThat(this.inspector -// .getInputWrapper(this.catalog.lookup(Function.class, "function"))) -// .isAssignableFrom(Map.class); + FunctionInvocationWrapper function = this.catalog.lookup("function"); + assertThat(function).isInstanceOf(Function.class); + Type inputType = function.getInputType(); + assertThat(FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(inputType))).isAssignableFrom(Map.class); } @Test @@ -430,14 +341,10 @@ public class ContextFunctionCatalogAutoConfigurationTests { try { create("greeter.jar", ComponentScanJarConfiguration.class); assertThat(this.context.getBean("greeter")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "greeter")) - .isInstanceOf(Function.class); -// assertThat(this.inspector -// .getInputType(this.catalog.lookup(Function.class, "greeter"))) -// .isAssignableFrom(String.class); -// assertThat(this.inspector -// .getInputWrapper(this.catalog.lookup(Function.class, "greeter"))) -// .isAssignableFrom(String.class); + FunctionInvocationWrapper function = this.catalog.lookup("greeter"); + assertThat(function).isInstanceOf(Function.class); + Type inputType = function.getInputType(); + assertThat((Class) FunctionTypeUtils.getGenericType(inputType)).isAssignableFrom(String.class); } finally { ClassUtils.overrideThreadContextClassLoader(getClass().getClassLoader()); @@ -465,9 +372,6 @@ public class ContextFunctionCatalogAutoConfigurationTests { .lookup(Function.class, "function"); assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO"); assertThat(bean).isNotSameAs(function); -// assertThat(this.inspector.getRegistration(function)).isNotNull(); -// assertThat(this.inspector.getRegistration(function).getType()) -// .isEqualTo(this.inspector.getRegistration(function).getType()); } @Test @@ -494,12 +398,9 @@ public class ContextFunctionCatalogAutoConfigurationTests { public void qualifiedBean() { create(QualifiedConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isNull(); - assertThat((Function) this.catalog.lookup(Function.class, "other")) - .isInstanceOf(Function.class); - assertThat( - this.inspector.getInputType(this.catalog.lookup(Function.class, "other"))) + assertThat((Function) this.catalog.lookup("function")).isNull(); + assertThat((Function) this.catalog.lookup("other")).isNotNull(); + assertThat(FunctionTypeUtils.getGenericType(((FunctionInvocationWrapper) this.catalog.lookup("other")).getInputType())) .isEqualTo(String.class); } @@ -518,12 +419,8 @@ public class ContextFunctionCatalogAutoConfigurationTests { public void registrationBean() { create(RegistrationConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) this.catalog.lookup(Function.class, "function")) - .isInstanceOf(Function.class); -// .isNull(); - assertThat((Function) this.catalog.lookup(Function.class, "registration")) - .isInstanceOf(Function.class); -// .isNull(); + assertThat((Function) this.catalog.lookup(Function.class, "function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "registration")).isInstanceOf(Function.class); assertThat((Function) this.catalog.lookup(Function.class, "other")) .isInstanceOf(Function.class); } @@ -557,7 +454,7 @@ public class ContextFunctionCatalogAutoConfigurationTests { private void create(Class[] types, String... props) { this.context = new SpringApplicationBuilder(types).properties(props).run(); this.catalog = this.context.getBean(FunctionCatalog.class); - this.inspector = this.context.getBean(FunctionInspector.class); +// this.inspector = this.context.getBean(FunctionInspector.class); } @EnableAutoConfiguration @@ -616,7 +513,7 @@ public class ContextFunctionCatalogAutoConfigurationTests { @Bean public BeanFactoryPostProcessor someBeanFactoryPostProcessor(Environment environment, - @Nullable FunctionRegistry functionCatalog, @Nullable FunctionInspector inspector) { + @Nullable FunctionRegistry functionCatalog) { return beanFactory -> { }; } } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/BasicStringConverter.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/BasicStringConverter.java index 1113422ef..e3634fd1c 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/BasicStringConverter.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/BasicStringConverter.java @@ -17,7 +17,8 @@ package org.springframework.cloud.function.web; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.cloud.function.context.catalog.FunctionInspector; +import org.springframework.cloud.function.context.catalog.FunctionTypeUtils; +import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; @@ -32,11 +33,7 @@ public class BasicStringConverter implements StringConverter { private ConfigurableListableBeanFactory registry; - private FunctionInspector inspector; - - public BasicStringConverter(FunctionInspector inspector, - ConfigurableListableBeanFactory registry) { - this.inspector = inspector; + public BasicStringConverter(ConfigurableListableBeanFactory registry) { this.registry = registry; } @@ -47,7 +44,8 @@ public class BasicStringConverter implements StringConverter { this.conversionService = conversionService != null ? conversionService : new DefaultConversionService(); } - Class type = this.inspector.getInputType(function); + //Class type = this.inspector.getInputType(function); + Class type = function == null ? Object.class : FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(((FunctionInvocationWrapper) function).getInputType())); return this.conversionService.canConvert(String.class, type) ? this.conversionService.convert(value, type) : value; } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RequestProcessor.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RequestProcessor.java index 7c1d38754..a5ddf383a 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RequestProcessor.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RequestProcessor.java @@ -41,7 +41,6 @@ import reactor.core.publisher.Mono; import org.springframework.beans.factory.ObjectProvider; import org.springframework.cloud.function.context.FunctionCatalog; -import org.springframework.cloud.function.context.catalog.FunctionInspector; import org.springframework.cloud.function.context.catalog.FunctionTypeUtils; import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; import org.springframework.cloud.function.context.config.RoutingFunction; @@ -81,7 +80,6 @@ public class RequestProcessor { private static Log logger = LogFactory.getLog(RequestProcessor.class); - private final FunctionInspector inspector; private final FunctionCatalog functionCatalog; @@ -91,12 +89,10 @@ public class RequestProcessor { private final List> messageReaders; - public RequestProcessor(FunctionInspector inspector, - FunctionCatalog functionCatalog, + public RequestProcessor(FunctionCatalog functionCatalog, ObjectProvider mapper, StringConverter converter, ObjectProvider codecs) { this.mapper = mapper.getIfAvailable(); - this.inspector = inspector; this.functionCatalog = functionCatalog; this.converter = converter; ServerCodecConfigurer source = codecs.getIfAvailable(); @@ -141,7 +137,9 @@ public class RequestProcessor { public Mono> post(FunctionWrapper wrapper, String body, boolean stream) { Object function = wrapper.handler(); - Class inputType = this.inspector.getInputType(function); + Class inputType = function == null + ? Object.class + : FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(((FunctionInvocationWrapper) function).getInputType())); Type itemType = getItemType(function); Object input = body == null && inputType.isAssignableFrom(String.class) ? "" : body; @@ -218,9 +216,10 @@ public class RequestProcessor { Function function = wrapper.function(); Flux flux; + Class inputType = function == null ? Object.class : FunctionTypeUtils + .getRawType(FunctionTypeUtils.getGenericType(((FunctionInvocationWrapper) wrapper.handler()).getInputType())); if (body != null) { - if (Collection.class - .isAssignableFrom(this.inspector.getInputType(wrapper.handler()))) { + if (Collection.class.isAssignableFrom(inputType)) { flux = Flux.just(body); } else if (body instanceof Flux) { @@ -233,8 +232,7 @@ public class RequestProcessor { flux = Flux.fromIterable(iterable); } } - else if (MultiValueMap.class - .isAssignableFrom(this.inspector.getInputType(wrapper.handler()))) { + else if (MultiValueMap.class.isAssignableFrom(inputType)) { flux = Flux.just(wrapper.params()); } else { @@ -261,7 +259,6 @@ public class RequestProcessor { } else if (function instanceof FunctionInvocationWrapper) { Publisher result = (Publisher) function.apply(flux); -// Publisher result = null; if (((FunctionInvocationWrapper) function).isConsumer()) { if (result != null) { ((Mono) result).subscribe(); @@ -342,26 +339,41 @@ public class RequestProcessor { private boolean isInputMultiple(Object handler) { - Class type = this.inspector.getInputType(handler); - Class wrapper = this.inspector.getInputWrapper(handler); - return Collection.class.isAssignableFrom(type) || Flux.class.equals(wrapper); + FunctionInvocationWrapper function = (FunctionInvocationWrapper) handler; + Class type = function == null ? Object.class : FunctionTypeUtils + .getRawType(FunctionTypeUtils.getGenericType(function.getInputType())); + return Collection.class.isAssignableFrom(type) || (function != null && FunctionTypeUtils.isFlux(function.getInputType())); + } private boolean isOutputSingle(Object handler) { - Class type = this.inspector.getOutputType(handler); - Class wrapper = this.inspector.getOutputWrapper(handler); + FunctionInvocationWrapper function = (FunctionInvocationWrapper) handler; + Type outputType = function.getOutputType(); +// if (function.isOutputTypePublisher()) { +// outputType = FunctionTypeUtils.getGenericType(outputType); +// } +// if (function.isOutputTypeMessage()) { +// outputType = FunctionTypeUtils.getGenericType(outputType); +// } + Class type = FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(outputType)); +// Class type1 = this.inspector.getOutputType(handler); +// Class wrapper1 = this.inspector.getOutputWrapper(handler); + Class wrapper = function.isOutputTypePublisher() ? FunctionTypeUtils.getRawType(outputType) : type; if (Stream.class.isAssignableFrom(type)) { return false; } else { + return wrapper == type || Mono.class.equals(wrapper) || Optional.class.equals(wrapper); } } private Publisher body(Object handler, ServerWebExchange exchange) { - ResolvableType elementType = ResolvableType - .forClass(this.inspector.getInputType(handler)); + FunctionInvocationWrapper function = (FunctionInvocationWrapper) handler; + Class inputType = FunctionTypeUtils + .getRawType(FunctionTypeUtils.getGenericType(function.getInputType())); + ResolvableType elementType = ResolvableType.forClass(inputType); // we effectively delegate type conversion to FunctionCatalog elementType = ResolvableType.forClass(String.class); diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/ReactorAutoConfiguration.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/ReactorAutoConfiguration.java index 2c1fbff83..d7b22b907 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/ReactorAutoConfiguration.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/ReactorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.cloud.function.context.FunctionCatalog; -import org.springframework.cloud.function.context.catalog.FunctionInspector; import org.springframework.cloud.function.web.BasicStringConverter; import org.springframework.cloud.function.web.RequestProcessor; import org.springframework.cloud.function.web.StringConverter; @@ -55,9 +54,8 @@ public class ReactorAutoConfiguration { @Bean @ConditionalOnMissingBean - public StringConverter functionStringConverter(FunctionInspector inspector, - ConfigurableListableBeanFactory beanFactory) { - return new BasicStringConverter(inspector, beanFactory); + public StringConverter functionStringConverter(ConfigurableListableBeanFactory beanFactory) { + return new BasicStringConverter(beanFactory); } } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/function/FunctionEndpointInitializer.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/function/FunctionEndpointInitializer.java index 9a98d60e9..78d1c0a4f 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/function/FunctionEndpointInitializer.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/function/FunctionEndpointInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -38,7 +38,7 @@ import org.springframework.boot.web.reactive.error.DefaultErrorAttributes; import org.springframework.boot.web.reactive.error.ErrorAttributes; import org.springframework.cloud.function.context.FunctionCatalog; import org.springframework.cloud.function.context.FunctionalSpringApplication; -import org.springframework.cloud.function.context.catalog.FunctionInspector; +import org.springframework.cloud.function.context.catalog.FunctionTypeUtils; import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; import org.springframework.cloud.function.context.config.ContextFunctionCatalogInitializer; import org.springframework.cloud.function.json.JsonMapper; @@ -104,15 +104,14 @@ class FunctionEndpointInitializer implements ApplicationContextInitializer new BasicStringConverter(context.getBean(FunctionInspector.class), context.getBeanFactory())); + () -> new BasicStringConverter(context.getBeanFactory())); context.registerBean(RequestProcessor.class, - () -> new RequestProcessor(context.getBean(FunctionInspector.class), + () -> new RequestProcessor( context.getBean(FunctionCatalog.class), context.getBeanProvider(JsonMapper.class), context.getBean(StringConverter.class), context.getBeanProvider(ServerCodecConfigurer.class))); context.registerBean(FunctionEndpointFactory.class, - () -> new FunctionEndpointFactory(context.getBean(FunctionCatalog.class), - context.getBean(FunctionInspector.class), context.getBean(RequestProcessor.class), + () -> new FunctionEndpointFactory(context.getBean(FunctionCatalog.class), context.getBean(RequestProcessor.class), context.getEnvironment())); context.registerBean(RouterFunction.class, () -> context.getBean(FunctionEndpointFactory.class).functionEndpoints()); @@ -199,18 +198,18 @@ class FunctionEndpointFactory { private final String handler; - private final FunctionInspector inspector; +// private final FunctionInspector inspector; private final RequestProcessor processor; - FunctionEndpointFactory(FunctionCatalog functionCatalog, FunctionInspector inspector, RequestProcessor processor, + FunctionEndpointFactory(FunctionCatalog functionCatalog, RequestProcessor processor, Environment environment) { String handler = environment.resolvePlaceholders("${function.handler}"); if (handler.startsWith("$")) { handler = null; } this.processor = processor; - this.inspector = inspector; +// this.inspector = inspector; this.functionCatalog = functionCatalog; this.handler = handler; } @@ -233,9 +232,12 @@ class FunctionEndpointFactory { @SuppressWarnings({ "unchecked" }) public RouterFunction functionEndpoints() { return route(POST("/**"), request -> { - Function, Flux> function = (Function, Flux>) extract(request); - Class outputType = (Class) this.inspector.getOutputType(function); - FunctionWrapper wrapper = RequestProcessor.wrapper(function, null, null); + Object function = extract(request); + FunctionInvocationWrapper funcWrapper = (FunctionInvocationWrapper) function; + Class outputType = funcWrapper == null + ? Object.class + : FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(funcWrapper.getOutputType())); + FunctionWrapper wrapper = RequestProcessor.wrapper((Function, Flux>) function, null, null); Mono> stream = request.bodyToMono(String.class) .flatMap(content -> this.processor.post(wrapper, content, false)); return stream.flatMap(entity -> { @@ -245,7 +247,8 @@ class FunctionEndpointFactory { }) .andRoute(GET("/**"), request -> { Object functionComponent = extract(request); - Class outputType = (Class) this.inspector.getOutputType(functionComponent); + FunctionInvocationWrapper funcWrapper = (FunctionInvocationWrapper) functionComponent; + Class outputType = FunctionTypeUtils.getRawType(FunctionTypeUtils.getGenericType(funcWrapper.getOutputType())); if (((FunctionInvocationWrapper) functionComponent).isSupplier()) { Supplier> supplier = (Supplier>) functionComponent; FunctionWrapper wrapper = RequestProcessor.wrapper(null, null, supplier); diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/ReactorAutoConfiguration.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/ReactorAutoConfiguration.java index d10b4bfe3..716b8f890 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/ReactorAutoConfiguration.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/ReactorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,7 +27,6 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat import org.springframework.boot.autoconfigure.gson.GsonAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.cloud.function.context.FunctionCatalog; -import org.springframework.cloud.function.context.catalog.FunctionInspector; import org.springframework.cloud.function.web.BasicStringConverter; import org.springframework.cloud.function.web.RequestProcessor; import org.springframework.cloud.function.web.StringConverter; @@ -55,9 +54,8 @@ public class ReactorAutoConfiguration { @Bean @ConditionalOnMissingBean - public StringConverter functionStringConverter(FunctionInspector inspector, - ConfigurableListableBeanFactory beanFactory) { - return new BasicStringConverter(inspector, beanFactory); + public StringConverter functionStringConverter(ConfigurableListableBeanFactory beanFactory) { + return new BasicStringConverter(beanFactory); } }