GH-1106 Fix RoutingFunction fail when "spring.cloud.function.definition" header contains a List value instead of a String value (GCP-specific)
Resolves #1106 Resolves #1146
This commit is contained in:
@@ -16,9 +16,11 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.function.context.config;
|
package org.springframework.cloud.function.context.config;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
@@ -193,11 +195,31 @@ public class RoutingFunction implements Function<Object, Object> {
|
|||||||
|
|
||||||
private FunctionInvocationWrapper locateFunctionFromDefinitionOrExpression(Message<?> message) {
|
private FunctionInvocationWrapper locateFunctionFromDefinitionOrExpression(Message<?> message) {
|
||||||
for (Entry<String, Object> headerEntry : message.getHeaders().entrySet()) {
|
for (Entry<String, Object> headerEntry : message.getHeaders().entrySet()) {
|
||||||
if (headerEntry.getKey().equalsIgnoreCase(FunctionProperties.FUNCTION_DEFINITION)) {
|
String headerKey = headerEntry.getKey();
|
||||||
return functionFromDefinition((String) headerEntry.getValue());
|
Object headerValue = headerEntry.getValue();
|
||||||
|
|
||||||
|
if (headerKey == null || headerValue == null) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else if (headerEntry.getKey().equalsIgnoreCase(FunctionProperties.ROUTING_EXPRESSION)) {
|
|
||||||
return this.functionFromExpression((String) headerEntry.getValue(), message, true);
|
boolean isFunctionDefinition = FunctionProperties.FUNCTION_DEFINITION.equalsIgnoreCase(headerKey);
|
||||||
|
boolean isRoutingExpression = FunctionProperties.ROUTING_EXPRESSION.equalsIgnoreCase(headerKey);
|
||||||
|
|
||||||
|
if (isFunctionDefinition) {
|
||||||
|
if (headerValue instanceof String definition) {
|
||||||
|
return functionFromDefinition(definition);
|
||||||
|
}
|
||||||
|
else if (headerValue instanceof List<?> definitions && !definitions.isEmpty()) {
|
||||||
|
return functionFromDefinition(definitions.stream().map(Object::toString).collect(Collectors.joining(",")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isRoutingExpression) {
|
||||||
|
if (headerValue instanceof String expression) {
|
||||||
|
return functionFromExpression(expression, message, true);
|
||||||
|
}
|
||||||
|
else if (headerValue instanceof List<?> expressions && !expressions.isEmpty()) {
|
||||||
|
return functionFromExpression(expressions.get(0).toString(), message, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package org.springframework.cloud.function.context.config;
|
package org.springframework.cloud.function.context.config;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
@@ -98,7 +99,7 @@ public class RoutingFunctionTests {
|
|||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
@Test
|
@Test
|
||||||
public void testInvocationWithMessageAndHeader() {
|
public void testInvocationWithMessageAndStringHeader() {
|
||||||
FunctionCatalog functionCatalog = this.configureCatalog();
|
FunctionCatalog functionCatalog = this.configureCatalog();
|
||||||
Function function = functionCatalog.lookup(RoutingFunction.FUNCTION_NAME);
|
Function function = functionCatalog.lookup(RoutingFunction.FUNCTION_NAME);
|
||||||
assertThat(function).isNotNull();
|
assertThat(function).isNotNull();
|
||||||
@@ -107,6 +108,57 @@ public class RoutingFunctionTests {
|
|||||||
assertThat(function.apply(message)).isEqualTo("olleh");
|
assertThat(function.apply(message)).isEqualTo("olleh");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
@Test
|
||||||
|
public void testInvocationWithMessageAndListOfSingleElementHeader() {
|
||||||
|
FunctionCatalog functionCatalog = this.configureCatalog();
|
||||||
|
Function function = functionCatalog.lookup(RoutingFunction.FUNCTION_NAME);
|
||||||
|
assertThat(function).isNotNull();
|
||||||
|
Message<String> message = MessageBuilder.withPayload("hello")
|
||||||
|
.setHeader(FunctionProperties.PREFIX + ".definition", List.of("reverse"))
|
||||||
|
.build();
|
||||||
|
assertThat(function.apply(message)).isEqualTo("olleh");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
@Test
|
||||||
|
public void testCompositionWithMessageAndListOfMultipleElementsHeader() {
|
||||||
|
FunctionCatalog functionCatalog = this.configureCatalog();
|
||||||
|
Function function = functionCatalog.lookup(RoutingFunction.FUNCTION_NAME);
|
||||||
|
assertThat(function).isNotNull();
|
||||||
|
Message<String> message = MessageBuilder.withPayload("hello")
|
||||||
|
.setHeader(FunctionProperties.PREFIX + ".definition",
|
||||||
|
List.of("reverse", "uppercase"))
|
||||||
|
.build();
|
||||||
|
assertThat(function.apply(message)).isEqualTo("OLLEH");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
@Test
|
||||||
|
public void testInvocationWithMessageAndListOfSingleRoutingExpression() {
|
||||||
|
FunctionCatalog functionCatalog = this.configureCatalog();
|
||||||
|
Function function = functionCatalog.lookup(RoutingFunction.FUNCTION_NAME);
|
||||||
|
assertThat(function).isNotNull();
|
||||||
|
Message<String> message = MessageBuilder.withPayload("hello")
|
||||||
|
.setHeader(FunctionProperties.PREFIX + ".routing-expression",
|
||||||
|
List.of("'reverse'"))
|
||||||
|
.build();
|
||||||
|
assertThat(function.apply(message)).isEqualTo("olleh");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
@Test
|
||||||
|
public void testInvocationWithMessageAndListOfMultipleRoutingExpressions() {
|
||||||
|
FunctionCatalog functionCatalog = this.configureCatalog();
|
||||||
|
Function function = functionCatalog.lookup(RoutingFunction.FUNCTION_NAME);
|
||||||
|
assertThat(function).isNotNull();
|
||||||
|
Message<String> message = MessageBuilder.withPayload("hello")
|
||||||
|
.setHeader(FunctionProperties.PREFIX + ".routing-expression",
|
||||||
|
List.of("'uppercase'", "'reverse'"))
|
||||||
|
.build();
|
||||||
|
assertThat(function.apply(message)).isEqualTo("HELLO");
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
@Test
|
@Test
|
||||||
public void testRoutingSimpleInputWithReactiveFunctionWithMessageHeader() {
|
public void testRoutingSimpleInputWithReactiveFunctionWithMessageHeader() {
|
||||||
|
|||||||
Reference in New Issue
Block a user