From c43f081ef12d918b88783b2c5089e714eb3cfebd Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Wed, 19 Sep 2018 14:33:01 +0200 Subject: [PATCH] Cleanup and added more tests --- .../cloud/function/context/FunctionType.java | 168 +++++++++--------- ...ntextFunctionCatalogAutoConfiguration.java | 3 + .../ContextFunctionPostProcessorTests.java | 24 ++- 3 files changed, 109 insertions(+), 86 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 a0c4bd30d..c3789796f 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 @@ -61,31 +61,6 @@ public class FunctionType { this.message = messageType(); } - private Type functionType(Type type) { - if (Supplier.class.isAssignableFrom(extractClass(type, ParamType.OUTPUT))) { - Type product = extractType(type, ParamType.OUTPUT, 0); - Class output = extractClass(product, ParamType.OUTPUT); - if (FunctionRegistration.class.isAssignableFrom(output)) { - type = extractType(product, ParamType.OUTPUT, 0); - } - else if (Function.class.isAssignableFrom(output) - || Supplier.class.isAssignableFrom(output) - || Consumer.class.isAssignableFrom(output)) { - type = product; - } - } - return type; - } - - private boolean messageType() { - Class inputType = findType(ParamType.INPUT_INNER_WRAPPER); - Class outputType = findType(ParamType.OUTPUT_INNER_WRAPPER); - return inputType.getName().startsWith(Message.class.getName()) - || Message.class.isAssignableFrom(inputType) - || outputType.getName().startsWith(Message.class.getName()) - || Message.class.isAssignableFrom(outputType); - } - public Type getType() { return type; } @@ -179,17 +154,19 @@ public class FunctionType { if (!isWrapper(input) && !isWrapper(output)) { return this; } - if (!isWrapper(input) || !isWrapper(output)) { + else if (isWrapper(input) && isWrapper(output)) { + if (input.isAssignableFrom(getInputWrapper()) + && output.isAssignableFrom(getOutputWrapper())) { + return this; + } + return new FunctionType(ResolvableType.forClassWithGenerics(Function.class, + wrapper(input, getInputType()), wrapper(output, getOutputType())) + .getType()); + } + else { throw new IllegalArgumentException("Both wrapper types must be wrappers in (" + input + ", " + output + ")"); } - if (input.isAssignableFrom(getInputWrapper()) - && output.isAssignableFrom(getOutputWrapper())) { - return this; - } - return new FunctionType(ResolvableType.forClassWithGenerics(Function.class, - wrapper(input, getInputType()), wrapper(output, getOutputType())) - .getType()); } public FunctionType wrap(Class wrapper) { @@ -212,6 +189,60 @@ public class FunctionType { .getType()); } + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((inputType == null) ? 0 : inputType.toString().hashCode()); + result = prime * result + + ((inputWrapper == null) ? 0 : inputWrapper.toString().hashCode()); + result = prime * result + (message ? 1231 : 1237); + result = prime * result + + ((outputType == null) ? 0 : outputType.toString().hashCode()); + result = prime * result + + ((outputWrapper == null) ? 0 : outputWrapper.toString().hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + FunctionType other = (FunctionType) obj; + if (inputType == null) { + if (other.inputType != null) + return false; + } + else if (!inputType.toString().equals(other.inputType.toString())) + return false; + if (inputWrapper == null) { + if (other.inputWrapper != null) + return false; + } + else if (!inputWrapper.toString().equals(other.inputWrapper.toString())) + return false; + if (message != other.message) + return false; + if (outputType == null) { + if (other.outputType != null) + return false; + } + else if (!outputType.toString().equals(other.outputType.toString())) + return false; + if (outputWrapper == null) { + if (other.outputWrapper != null) + return false; + } + else if (!outputWrapper.toString().equals(other.outputWrapper.toString())) + return false; + return true; + } + private ResolvableType wrapper(Class wrapper, Class type) { return wrap(this, wrapper, type); } @@ -383,58 +414,29 @@ public class FunctionType { return param; } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((inputType == null) ? 0 : inputType.toString().hashCode()); - result = prime * result - + ((inputWrapper == null) ? 0 : inputWrapper.toString().hashCode()); - result = prime * result + (message ? 1231 : 1237); - result = prime * result - + ((outputType == null) ? 0 : outputType.toString().hashCode()); - result = prime * result - + ((outputWrapper == null) ? 0 : outputWrapper.toString().hashCode()); - return result; + private Type functionType(Type type) { + if (Supplier.class.isAssignableFrom(extractClass(type, ParamType.OUTPUT))) { + Type product = extractType(type, ParamType.OUTPUT, 0); + Class output = extractClass(product, ParamType.OUTPUT); + if (FunctionRegistration.class.isAssignableFrom(output)) { + type = extractType(product, ParamType.OUTPUT, 0); + } + else if (Function.class.isAssignableFrom(output) + || Supplier.class.isAssignableFrom(output) + || Consumer.class.isAssignableFrom(output)) { + type = product; + } + } + return type; } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - FunctionType other = (FunctionType) obj; - if (inputType == null) { - if (other.inputType != null) - return false; - } - else if (!inputType.toString().equals(other.inputType.toString())) - return false; - if (inputWrapper == null) { - if (other.inputWrapper != null) - return false; - } - else if (!inputWrapper.toString().equals(other.inputWrapper.toString())) - return false; - if (message != other.message) - return false; - if (outputType == null) { - if (other.outputType != null) - return false; - } - else if (!outputType.toString().equals(other.outputType.toString())) - return false; - if (outputWrapper == null) { - if (other.outputWrapper != null) - return false; - } - else if (!outputWrapper.toString().equals(other.outputWrapper.toString())) - return false; - return true; + private boolean messageType() { + Class inputType = findType(ParamType.INPUT_INNER_WRAPPER); + Class outputType = findType(ParamType.OUTPUT_INNER_WRAPPER); + return inputType.getName().startsWith(Message.class.getName()) + || Message.class.isAssignableFrom(inputType) + || outputType.getName().startsWith(Message.class.getName()) + || Message.class.isAssignableFrom(outputType); } enum ParamType { 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 fbc252484..8082b17f9 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 @@ -327,6 +327,9 @@ public class ContextFunctionCatalogAutoConfiguration { @SuppressWarnings("unchecked") private Object compose(Object a, Object b) { if (a instanceof Supplier && b instanceof Function) { + if (b instanceof FluxConsumer) { + throw new UnsupportedOperationException("Composing Supplier and Consumer is not supported at the moment"); + } Supplier supplier = (Supplier) a; Function function = (Function) b; return (Supplier) () -> function.apply(supplier.get()); diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionPostProcessorTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionPostProcessorTests.java index 0c46fec09..426b60e39 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionPostProcessorTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionPostProcessorTests.java @@ -16,25 +16,25 @@ package org.springframework.cloud.function.context.config; +import static org.assertj.core.api.Assertions.assertThat; + import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import org.junit.After; import org.junit.Test; - import org.springframework.beans.BeanUtils; import org.springframework.cloud.function.context.FunctionRegistration; import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration.ContextFunctionRegistry; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.ClassUtils; -import static org.assertj.core.api.Assertions.assertThat; - import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -102,6 +102,24 @@ public class ContextFunctionPostProcessorTests { .containsExactly("foos|bars"); } + @Test + public void supplierAndFunction() { + processor.register(new FunctionRegistration>(() -> "foo", "supplier")); + processor.register(new FunctionRegistration>((x) -> x.toUpperCase(), "function")); + @SuppressWarnings("unchecked") + Supplier> supplier = (Supplier>) processor.lookupSupplier("supplier|function"); + assertThat(supplier.get().blockFirst()).isEqualTo("FOO"); + assertThat(processor.getRegistration(supplier).getNames()).containsExactly("supplier|function"); + } + + //TODO we should support it at some point since this is really a Runnable + @Test(expected=UnsupportedOperationException.class) + public void supplierAndConsumer() { + processor.register(new FunctionRegistration>(() -> "foo", "supplier")); + processor.register(new FunctionRegistration>(System.out::println, "consumer")); + processor.lookupSupplier("supplier|consumer"); + } + @Test public void compose() { processor.register(new FunctionRegistration<>(new Foos(), "foos"));