From ab68cb58e9f0be2cba6e95dcffdf14d381d9c66a Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Thu, 16 Apr 2020 21:05:20 +0200 Subject: [PATCH] Fix regression for implicit composition Also, added message check in AWS destination resolver --- .../aws/LambdaDestinationResolver.java | 10 ++++--- .../BeanFactoryAwareFunctionRegistry.java | 6 +++- .../catalog/InMemoryFunctionCatalog.java | 3 ++ .../catalog/SimpleFunctionRegistry.java | 30 +++++++++++++++++++ .../ContextFunctionCatalogInitializer.java | 1 - .../catalog/SimpleFunctionRegistryTests.java | 8 ++--- 6 files changed, 48 insertions(+), 10 deletions(-) diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/LambdaDestinationResolver.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/LambdaDestinationResolver.java index 1e6082aec..2a756d50a 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/LambdaDestinationResolver.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/LambdaDestinationResolver.java @@ -26,10 +26,12 @@ public class LambdaDestinationResolver implements DestinationResolver { @Override public String destination(Supplier supplier, String name, Object value) { - Message message = (Message) value; - MessageHeaders headers = message.getHeaders(); - if (headers.containsKey("lambda-runtime-aws-request-id")) { - return (String) headers.get("lambda-runtime-aws-request-id"); + if (value instanceof Message) { + Message message = (Message) value; + MessageHeaders headers = message.getHeaders(); + if (headers.containsKey("lambda-runtime-aws-request-id")) { + return (String) headers.get("lambda-runtime-aws-request-id"); + } } return "unknown"; } 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 b2ceec653..c8c0fefbe 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 @@ -154,7 +154,7 @@ public class BeanFactoryAwareFunctionRegistry extends SimpleFunctionRegistry imp @Override String discoverDefaultDefinitionIfNecessary(String definition) { - if (StringUtils.isEmpty(definition)) { + if (StringUtils.isEmpty(definition) || definition.endsWith("|")) { // the underscores are for Kotlin function registrations (see KotlinLambdaToFunctionAutoConfiguration) String[] functionNames = Stream.of(this.applicationContext.getBeanNamesForType(Function.class)) .filter(n -> !n.endsWith(FunctionRegistration.REGISTRATION_NAME_SUFFIX) && !n @@ -184,6 +184,10 @@ public class BeanFactoryAwareFunctionRegistry extends SimpleFunctionRegistry imp } definition = names.get(0); } + else if (definition.endsWith("|")) { + Set fNames = this.getNames(null); + definition = this.determinImpliedDefinition(fNames, definition); + } else { definition = this.discoverDefaultDefinitionFromRegistration(); } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/InMemoryFunctionCatalog.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/InMemoryFunctionCatalog.java index 5e9cfbd6c..ed9302007 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/InMemoryFunctionCatalog.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/InMemoryFunctionCatalog.java @@ -27,7 +27,10 @@ import org.springframework.util.Assert; * @author Dave Syer * @author Mark Fisher * @author Oleg Zhurakousky + * + * @deprecated since 3.1. End-of-life. Not used by the framework anymore in favor of SimpleFunctionRegistry */ +@Deprecated public class InMemoryFunctionCatalog extends AbstractComposableFunctionRegistry { public InMemoryFunctionCatalog() { 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 36386b4f9..fbbd7b9b4 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 @@ -26,6 +26,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; @@ -48,6 +49,7 @@ import reactor.util.function.Tuples; import org.springframework.aop.framework.ProxyFactory; import org.springframework.aop.support.AopUtils; +import org.springframework.beans.factory.BeanFactory; import org.springframework.cloud.function.context.FunctionProperties; import org.springframework.cloud.function.context.FunctionRegistration; import org.springframework.cloud.function.context.FunctionRegistry; @@ -72,6 +74,11 @@ import org.springframework.util.StringUtils; /** + * + * Basic implementation of FunctionRegistry which maintains the cache of registered functions while + * decorating them with additional features such as transparent type conversion, composition, routing etc. + * + * Unlike {@link BeanFactoryAwareFunctionRegistry}, this implementation does not depend on {@link BeanFactory}. * * @author Oleg Zhurakousky * @@ -217,8 +224,31 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect else if (!this.registrationsByName.containsKey(definition) && this.registrationsByName.size() == 1) { definition = this.registrationsByName.keySet().iterator().next(); } + else if (definition.endsWith("|")) { + if (this.registrationsByName.size() == 2) { + Set fNames = this.getNames(null); + definition = this.determinImpliedDefinition(fNames, definition); + } + } return definition; + } + String determinImpliedDefinition(Set fNames, String originalDefinition) { + if (fNames.size() == 2) { + Iterator iter = fNames.iterator(); + String n1 = iter.next(); + String n2 = iter.next(); + String[] definitionName = StringUtils.delimitedListToStringArray(originalDefinition, "|"); + if (definitionName[0].equals(n1)) { + definitionName[1] = n2; + originalDefinition = definitionName[0] + "|" + definitionName[1]; + } + else { + definitionName[1] = n1; + originalDefinition = definitionName[0] + "|" + definitionName[1]; + } + } + return originalDefinition; } Type discovereFunctionTypeByName(String name) { diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java index be03b8ae2..f9e272bbf 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java @@ -169,7 +169,6 @@ public class ContextFunctionCatalogInitializer implements ApplicationContextInit } if (this.context.getBeanFactory().getBeanNamesForType(FunctionCatalog.class, false, false).length == 0) { - this.context.registerBean(SimpleFunctionRegistry.class, () -> { List messageConverters = new ArrayList<>(); JsonMapper jsonMapper = this.context.getBean(JsonMapper.class); diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistryTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistryTests.java index 6d6105178..aad1652a4 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistryTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistryTests.java @@ -28,6 +28,7 @@ import org.junit.Test; import reactor.core.publisher.Flux; import org.springframework.cloud.function.context.FunctionRegistration; +import org.springframework.cloud.function.context.FunctionRegistry; import org.springframework.cloud.function.context.FunctionType; import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; import org.springframework.cloud.function.context.config.JsonMessageConverter; @@ -103,21 +104,20 @@ public class SimpleFunctionRegistryTests { } @Test - @Ignore public void testFunctionCompositionImplicit() { FunctionRegistration wordsRegistration = new FunctionRegistration<>( new Words(), "words").type(FunctionType.of(Words.class)); FunctionRegistration reverseRegistration = new FunctionRegistration<>( new Reverse(), "reverse").type(FunctionType.of(Reverse.class)); - SimpleFunctionRegistry catalog = new SimpleFunctionRegistry(this.conversionService, this.messageConverter); + FunctionRegistry catalog = new SimpleFunctionRegistry(this.conversionService, this.messageConverter); catalog.register(wordsRegistration); catalog.register(reverseRegistration); // There's only one function, we should be able to leave that blank - Supplier> lookedUpFunction = catalog.lookup("words|"); + Supplier lookedUpFunction = catalog.lookup("words|"); assertThat(lookedUpFunction).isNotNull(); - assertThat(lookedUpFunction.get().blockFirst()).isEqualTo("olleh"); + assertThat(lookedUpFunction.get()).isEqualTo("olleh"); } @Test