From 5203401e008a9dd683a95a1a63a135a804d54f4a Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 26 Feb 2018 13:48:36 +0000 Subject: [PATCH] Use Void as input type for Supplier, etc. --- .../cloud/function/context/FunctionType.java | 16 ++++++++++ .../function/context/FunctionTypeTests.java | 26 ++++++++++++++++ ...FunctionCatalogAutoConfigurationTests.java | 30 +++++++++++-------- .../flux/BetterGsonHttpMessageConverter.java | 2 -- .../flux/response/FluxReturnValueHandler.java | 3 +- 5 files changed, 62 insertions(+), 15 deletions(-) diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionType.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionType.java index 0143a76e6..cfc9b9384 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionType.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionType.java @@ -18,7 +18,9 @@ package org.springframework.cloud.function.context; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Optional; +import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; import org.reactivestreams.Publisher; @@ -219,6 +221,9 @@ public class FunctionType { if (type instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) type; if (parameterizedType.getActualTypeArguments().length == 1) { + if (isVoid(parameterizedType, paramType)) { + return Void.class; + } // There's only one index = 0; } @@ -245,6 +250,17 @@ public class FunctionType { return param; } + private boolean isVoid(ParameterizedType parameterizedType, ParamType paramType) { + Class rawType = extractClass(parameterizedType.getRawType(), paramType); + if (Consumer.class.isAssignableFrom(rawType) && paramType.isOutput()) { + return true; + } + if (Supplier.class.isAssignableFrom(rawType) && paramType.isInput()) { + return true; + } + return false; + } + private Type extractNestedType(ParamType paramType, Type param) { if (!paramType.isInnerWrapper() && param instanceof ParameterizedType) { if (((ParameterizedType) param).getRawType().getTypeName() diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/FunctionTypeTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/FunctionTypeTests.java index 9c9b37d68..1691f59a7 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/FunctionTypeTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/FunctionTypeTests.java @@ -18,7 +18,9 @@ package org.springframework.cloud.function.context; import java.lang.reflect.Type; import java.util.Collections; import java.util.Map; +import java.util.function.Consumer; import java.util.function.Function; +import java.util.function.Supplier; import org.junit.Test; @@ -99,6 +101,30 @@ public class FunctionTypeTests { assertThat(function.isMessage()).isEqualTo(false); } + @Test + public void pojoConsumerFromType() { + Type type = ResolvableType.forClassWithGenerics(Consumer.class, Foo.class) + .getType(); + FunctionType function = new FunctionType(type); + assertThat(function.getInputType()).isEqualTo(Foo.class); + assertThat(function.getOutputType()).isEqualTo(Void.class); + assertThat(function.getInputWrapper()).isEqualTo(Foo.class); + assertThat(function.getOutputWrapper()).isEqualTo(Void.class); + assertThat(function.isMessage()).isEqualTo(false); + } + + @Test + public void pojoSupplierFromType() { + Type type = ResolvableType.forClassWithGenerics(Supplier.class, Foo.class) + .getType(); + FunctionType function = new FunctionType(type); + assertThat(function.getInputType()).isEqualTo(Void.class); + assertThat(function.getOutputType()).isEqualTo(Foo.class); + assertThat(function.getInputWrapper()).isEqualTo(Void.class); + assertThat(function.getOutputWrapper()).isEqualTo(Foo.class); + assertThat(function.isMessage()).isEqualTo(false); + } + @Test public void plainFunctionFromApi() { FunctionType function = FunctionType.from(Integer.class).to(String.class); 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 5d93b6df2..38e435e93 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 @@ -136,9 +136,9 @@ public class ContextFunctionCatalogAutoConfigurationTests { assertThat(catalog.lookupFunction("names,foos")).isNull(); assertThat(inspector.getOutputType(catalog.lookupSupplier("names,foos"))) .isAssignableFrom(Foo.class); - // The input type is the same as the output type of the first element in the chain + // The input type is the same as the input type of the first element in the chain assertThat(inspector.getInputType(catalog.lookupSupplier("names,foos"))) - .isAssignableFrom(String.class); + .isAssignableFrom(Void.class); } @Test @@ -148,9 +148,9 @@ public class ContextFunctionCatalogAutoConfigurationTests { assertThat(catalog.lookupFunction("foos,print")).isNull(); assertThat(inspector.getInputType(catalog.lookupConsumer("foos,print"))) .isAssignableFrom(String.class); - // The output type is the same as the input type of the last element in the chain + // The output type is the same as the output type of the last element in the chain assertThat(inspector.getOutputType(catalog.lookupConsumer("foos,print"))) - .isAssignableFrom(Foo.class); + .isAssignableFrom(Void.class); } @Test @@ -543,7 +543,8 @@ public class ContextFunctionCatalogAutoConfigurationTests { @EnableAutoConfiguration @Configuration - protected static class SingletonMessageConfiguration implements BeanFactoryPostProcessor { + protected static class SingletonMessageConfiguration + implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) @@ -570,7 +571,8 @@ public class ContextFunctionCatalogAutoConfigurationTests { } - protected static class SingletonMessageFunction implements Function, Message> { + protected static class SingletonMessageFunction + implements Function, Message> { @Override public Message apply(Message input) { @@ -672,24 +674,28 @@ public class ContextFunctionCatalogAutoConfigurationTests { @EnableAutoConfiguration @Configuration - protected static class FactoryBeanConfiguration implements BeanDefinitionRegistryPostProcessor { + protected static class FactoryBeanConfiguration + implements BeanDefinitionRegistryPostProcessor { @Override - public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { - RootBeanDefinition beanDefinition = new RootBeanDefinition(FunctionFactoryBean.class); + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) + throws BeansException { + RootBeanDefinition beanDefinition = new RootBeanDefinition( + FunctionFactoryBean.class); beanDefinition.setSource(new DescriptiveResource("Function")); registry.registerBeanDefinition("function", beanDefinition); } @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) + throws BeansException { } } - - private static class FunctionFactoryBean extends AbstractFactoryBean> { + private static class FunctionFactoryBean + extends AbstractFactoryBean> { @Override public Class getObjectType() { diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/BetterGsonHttpMessageConverter.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/BetterGsonHttpMessageConverter.java index ca09c4550..aaf31dc49 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/BetterGsonHttpMessageConverter.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/BetterGsonHttpMessageConverter.java @@ -114,7 +114,6 @@ public class BetterGsonHttpMessageConverter } @Override - @SuppressWarnings("deprecation") public Object read(Type type, Class contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { @@ -123,7 +122,6 @@ public class BetterGsonHttpMessageConverter } @Override - @SuppressWarnings("deprecation") protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/response/FluxReturnValueHandler.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/response/FluxReturnValueHandler.java index 93a27b7e8..6489efe23 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/response/FluxReturnValueHandler.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/response/FluxReturnValueHandler.java @@ -165,7 +165,8 @@ public class FluxReturnValueHandler implements AsyncHandlerMethodReturnValueHand } MediaType mediaType = null; - if (isPlainText(webRequest) && CharSequence.class.isAssignableFrom(type)) { + if (isPlainText(webRequest) && (CharSequence.class.isAssignableFrom(type) + || Void.class.isAssignableFrom(type))) { mediaType = MediaType.TEXT_PLAIN; } else {