Add support for SimpleEvaluationContext to RoutingFunction

This commit is contained in:
Oleg Zhurakousky
2022-03-29 15:14:42 +02:00
parent bf122213e4
commit bcb2a25a28
2 changed files with 34 additions and 20 deletions

View File

@@ -33,6 +33,8 @@ import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.DataBindingPropertyAccessor;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.messaging.Message;
import org.springframework.util.Assert;
@@ -59,6 +61,9 @@ public class RoutingFunction implements Function<Object, Object> {
private final StandardEvaluationContext evalContext = new StandardEvaluationContext();
private final SimpleEvaluationContext headerEvalContext = SimpleEvaluationContext
.forPropertyAccessors(DataBindingPropertyAccessor.forReadOnlyAccess()).build();
private final SpelExpressionParser spelParser = new SpelExpressionParser();
private final FunctionCatalog functionCatalog;
@@ -123,13 +128,13 @@ public class RoutingFunction implements Function<Object, Object> {
}
}
else if (StringUtils.hasText((String) message.getHeaders().get("spring.cloud.function.routing-expression"))) {
function = this.functionFromExpression((String) message.getHeaders().get("spring.cloud.function.routing-expression"), message);
function = this.functionFromExpression((String) message.getHeaders().get("spring.cloud.function.routing-expression"), message, true);
if (function.isInputTypePublisher()) {
this.assertOriginalInputIsNotPublisher(originalInputIsPublisher);
}
}
else if (StringUtils.hasText(functionProperties.getRoutingExpression())) {
function = this.functionFromExpression(functionProperties.getRoutingExpression(), message);
function = this.functionFromExpression(functionProperties.getRoutingExpression(), message, false);
}
else if (StringUtils.hasText(functionProperties.getDefinition())) {
function = this.functionFromDefinition(functionProperties.getDefinition());
@@ -147,7 +152,7 @@ public class RoutingFunction implements Function<Object, Object> {
function = functionFromDefinition(functionProperties.getDefinition());
}
else if (StringUtils.hasText(functionProperties.getRoutingExpression())) {
function = this.functionFromExpression(functionProperties.getRoutingExpression(), input);
function = this.functionFromExpression(functionProperties.getRoutingExpression(), input, false);
}
else {
return input instanceof Mono
@@ -159,7 +164,7 @@ public class RoutingFunction implements Function<Object, Object> {
else {
this.assertOriginalInputIsNotPublisher(originalInputIsPublisher);
if (StringUtils.hasText(functionProperties.getRoutingExpression())) {
function = this.functionFromExpression(functionProperties.getRoutingExpression(), input);
function = this.functionFromExpression(functionProperties.getRoutingExpression(), input, false);
}
else
if (StringUtils.hasText(functionProperties.getDefinition())) {
@@ -181,20 +186,6 @@ public class RoutingFunction implements Function<Object, Object> {
+ "spring.cloud.function.routing-expression' as application properties.");
}
// private FunctionInvocationWrapper functionFromCallback(Object input) {
// if (input instanceof Message) {
// Object routingResult = this.routingCallback.functionDefinition((Message<?>) input);
// if (routingResult != null && routingResult instanceof String) {
//
// }
// if (StringUtils.hasText(functionDefinition)) {
// return this.functionFromDefinition(functionDefinition);
// }
// }
// logger.info("Unable to determine route-to function from the provided MessageRoutingCallback");
// return null;
// }
private FunctionInvocationWrapper functionFromDefinition(String definition) {
FunctionInvocationWrapper function = functionCatalog.lookup(definition);
Assert.notNull(function, "Failed to lookup function to route based on the value of 'spring.cloud.function.definition' property '"
@@ -205,9 +196,10 @@ public class RoutingFunction implements Function<Object, Object> {
return function;
}
private FunctionInvocationWrapper functionFromExpression(String routingExpression, Object input) {
private FunctionInvocationWrapper functionFromExpression(String routingExpression, Object input, boolean isViaHeader) {
Expression expression = spelParser.parseExpression(routingExpression);
String functionName = expression.getValue(this.evalContext, input, String.class);
// String functionName = expression.getValue(this.evalContext, input, String.class);
String functionName = isViaHeader ? expression.getValue(this.headerEvalContext, input, String.class) : expression.getValue(this.evalContext, input, String.class);
Assert.hasText(functionName, "Failed to resolve function name based on routing expression '" + functionProperties.getRoutingExpression() + "'");
FunctionInvocationWrapper function = functionCatalog.lookup(functionName);
Assert.notNull(function, "Failed to lookup function to route to based on the expression '"

View File

@@ -35,6 +35,7 @@ import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
/**
*
@@ -183,6 +184,27 @@ public class RoutingFunctionTests {
assertThat(function.apply(message)).isEqualTo("OLLEH");
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Test
public void failWithHeaderProvidedExpressionAccessingRuntime() {
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",
"T(java.lang.Runtime).getRuntime().exec(\"open -a calculator.app\")")
.build();
try {
function.apply(message);
fail("Function shoudl not succeed");
}
catch (Exception e) {
assertThat(e.getMessage()).isEqualTo("EL1005E: Type cannot be found 'java.lang.Runtime'");
}
}
@EnableAutoConfiguration
@Configuration
protected static class RoutingFunctionConfiguration {