INT-4443: Use SimpleEC for uriVariablesExpression
JIRA: https://jira.spring.io/browse/INT-4443 **cherry-pick to 5.0.x, 4.3.x** Polishing; use data binding accessor in test evaluation contexts. Add `.withInstanceMethods()` See https://jira.spring.io/browse/SPR-16588?focusedCommentId=158041&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-158041 * Polishing according PR comments
This commit is contained in:
committed by
Artem Bilan
parent
7b86ca7bc8
commit
1cd6c11808
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -68,6 +68,7 @@ public class HttpOutboundChannelAdapterParser extends AbstractOutboundChannelAda
|
||||
}
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "charset");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "extract-payload");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "trusted-spel");
|
||||
HttpAdapterParsingUtils.setExpectedResponseOrExpression(element, parserContext, builder);
|
||||
HttpAdapterParsingUtils.configureUriVariableExpressions(builder, parserContext, element);
|
||||
return builder.getBeanDefinition();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -76,6 +76,7 @@ public class HttpOutboundGatewayParser extends AbstractConsumerEndpointParser {
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "charset");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "extract-request-payload",
|
||||
"extractPayload");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "trusted-spel");
|
||||
|
||||
HttpAdapterParsingUtils.setExpectedResponseOrExpression(element, parserContext, builder);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
* Copyright 2017-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,7 +31,9 @@ import java.util.function.Supplier;
|
||||
import javax.xml.transform.Source;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.support.SimpleEvaluationContext;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@@ -68,6 +70,7 @@ import org.springframework.web.util.UriComponentsBuilder;
|
||||
* @author Artem Bilan
|
||||
* @author Wallace Wadge
|
||||
* @author Shiliang Li
|
||||
*
|
||||
* @since 5.0
|
||||
*/
|
||||
public abstract class AbstractHttpRequestExecutingMessageHandler extends AbstractReplyProducingMessageHandler {
|
||||
@@ -77,10 +80,14 @@ public abstract class AbstractHttpRequestExecutingMessageHandler extends Abstrac
|
||||
|
||||
private final Map<String, Expression> uriVariableExpressions = new HashMap<>();
|
||||
|
||||
private volatile StandardEvaluationContext evaluationContext;
|
||||
|
||||
private final Expression uriExpression;
|
||||
|
||||
private StandardEvaluationContext evaluationContext;
|
||||
|
||||
private SimpleEvaluationContext simpleEvaluationContext;
|
||||
|
||||
private boolean trustedSpel;
|
||||
|
||||
private volatile boolean encodeUri = true;
|
||||
|
||||
private volatile Expression httpMethodExpression = new ValueExpression<>(HttpMethod.POST);
|
||||
@@ -247,9 +254,21 @@ public abstract class AbstractHttpRequestExecutingMessageHandler extends Abstrac
|
||||
this.transferCookies = transferCookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if you trust the source of SpEL expressions used to evaluate URI
|
||||
* variables. Default is false, which means a {@link SimpleEvaluationContext} is used
|
||||
* for evaluating such expressions, which restricts the use of some SpEL capabilities.
|
||||
* @param trustedSpel true to trust.
|
||||
* @since 4.3.15.
|
||||
*/
|
||||
public void setTrustedSpel(boolean trustedSpel) {
|
||||
this.trustedSpel = trustedSpel;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doInit() {
|
||||
this.evaluationContext = ExpressionUtils.createStandardEvaluationContext(this.getBeanFactory());
|
||||
this.simpleEvaluationContext = ExpressionUtils.createSimpleEvaluationContext(this.getBeanFactory());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -526,18 +545,22 @@ public abstract class AbstractHttpRequestExecutingMessageHandler extends Abstrac
|
||||
private Map<String, ?> determineUriVariables(Message<?> requestMessage) {
|
||||
Map<String, ?> expressions;
|
||||
|
||||
EvaluationContext evaluationContextToUse = this.evaluationContext;
|
||||
if (this.uriVariablesExpression != null) {
|
||||
Object expressionsObject = this.uriVariablesExpression.getValue(this.evaluationContext, requestMessage);
|
||||
Assert.state(expressionsObject instanceof Map,
|
||||
"The 'uriVariablesExpression' evaluation must result in a 'Map'.");
|
||||
expressions = (Map<String, ?>) expressionsObject;
|
||||
if (!this.trustedSpel) {
|
||||
evaluationContextToUse = this.simpleEvaluationContext;
|
||||
}
|
||||
}
|
||||
else {
|
||||
expressions = this.uriVariableExpressions;
|
||||
}
|
||||
|
||||
return ExpressionEvalMap.from(expressions)
|
||||
.usingEvaluationContext(this.evaluationContext)
|
||||
.usingEvaluationContext(evaluationContextToUse)
|
||||
.withRoot(requestMessage)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -398,6 +398,18 @@
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="trusted-spel">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Set to 'true' if you trust SpEL expressions that might be evaluated to generate
|
||||
URI variables.
|
||||
The default value is 'false'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:union memberTypes="xsd:boolean xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
@@ -490,6 +502,18 @@
|
||||
</xsd:attribute>
|
||||
<xsd:attributeGroup ref="httpOutboundCommonAttributes"/>
|
||||
<xsd:attributeGroup ref="syncHttpOutboundCommonAttributes"/>
|
||||
<xsd:attribute name="trusted-spel">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Set to 'true' if you trust SpEL expressions that might be evaluated to generate
|
||||
URI variables.
|
||||
The default value is 'false'.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:union memberTypes="xsd:boolean xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<si:chain input-channel="httpOutboundChannelAdapterWithinChain">
|
||||
<outbound-channel-adapter url="http://localhost/test1/%2f" encode-uri="false" rest-template="restTemplate"/>
|
||||
<si:chain id="chain" input-channel="httpOutboundChannelAdapterWithinChain">
|
||||
<outbound-channel-adapter id="adapter" url="http://localhost/test1/%2f" encode-uri="false" rest-template="restTemplate"
|
||||
trusted-spel="true" />
|
||||
</si:chain>
|
||||
|
||||
<beans:bean id="restTemplate" class="org.mockito.Mockito" factory-method="spy">
|
||||
@@ -22,6 +23,7 @@
|
||||
<outbound-gateway url="http://localhost:51235/%2f/testApps?param={param}"
|
||||
rest-template="restTemplate"
|
||||
encode-uri="false"
|
||||
trusted-spel="true"
|
||||
expected-response-type-expression="T (org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandlerTests).testParameterizedTypeReference()">
|
||||
<uri-variable name="param" expression="T(java.net.URLEncoder).encode('http Outbound Gateway Within Chain', 'UTF-8')"/>
|
||||
</outbound-gateway>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,9 +16,11 @@
|
||||
|
||||
package org.springframework.integration.http.outbound;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -706,6 +708,9 @@ public class HttpRequestExecutingMessageHandlerTests {
|
||||
channel.send(MessageBuilder.withPayload("test").build());
|
||||
Mockito.verify(restTemplate).exchange(Mockito.eq(new URI("http://localhost/test1/%2f")),
|
||||
Mockito.eq(HttpMethod.POST), Mockito.any(HttpEntity.class), Mockito.<Class<Object>>eq(null));
|
||||
HttpRequestExecutingMessageHandler handler = ctx.getBean("chain$child.adapter.handler",
|
||||
HttpRequestExecutingMessageHandler.class);
|
||||
assertThat(TestUtils.getPropertyValue(handler, "trustedSpel"), equalTo(Boolean.TRUE));
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.springframework.integration.http.outbound;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
@@ -132,13 +134,15 @@ public class UriVariableExpressionTests {
|
||||
handler.setUriVariablesExpression(new SpelExpressionParser().parseExpression("headers.uriVariables"));
|
||||
handler.afterPropertiesSet();
|
||||
|
||||
Map<String, String> expressions = new HashMap<String, String>();
|
||||
Map<String, Object> expressions = new HashMap<String, Object>();
|
||||
expressions.put("foo", "bar");
|
||||
|
||||
Map<String, ?> expressionsMap = ExpressionEvalMap.from(expressions).usingSimpleCallback().build();
|
||||
|
||||
try {
|
||||
handler.handleMessage(MessageBuilder.withPayload("test").setHeader("uriVariables", expressionsMap).build());
|
||||
handler.handleMessage(MessageBuilder.withPayload("test")
|
||||
.setHeader("uriVariables", expressionsMap)
|
||||
.build());
|
||||
fail("Exception expected.");
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -146,6 +150,42 @@ public class UriVariableExpressionTests {
|
||||
}
|
||||
|
||||
assertEquals("http://test/bar", uriHolder.get().toString());
|
||||
|
||||
expressions.put("foo", new SpelExpressionParser().parseExpression("'bar'.toUpperCase()"));
|
||||
try {
|
||||
handler.handleMessage(MessageBuilder.withPayload("test")
|
||||
.setHeader("uriVariables", expressions)
|
||||
.build());
|
||||
fail("Exception expected.");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertEquals("intentional", e.getCause().getMessage());
|
||||
}
|
||||
|
||||
assertEquals("http://test/BAR", uriHolder.get().toString());
|
||||
|
||||
expressions.put("foo", new SpelExpressionParser().parseExpression("T(Integer).valueOf('42')"));
|
||||
try {
|
||||
handler.handleMessage(MessageBuilder.withPayload("test")
|
||||
.setHeader("uriVariables", expressions)
|
||||
.build());
|
||||
fail("Exception expected.");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertThat(e.getCause().getMessage(), containsString("Type cannot be found"));
|
||||
}
|
||||
|
||||
handler.setTrustedSpel(true);
|
||||
try {
|
||||
handler.handleMessage(MessageBuilder.withPayload("test")
|
||||
.setHeader("uriVariables", expressions)
|
||||
.build());
|
||||
fail("Exception expected.");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertEquals("intentional", e.getCause().getMessage());
|
||||
}
|
||||
assertEquals("http://test/42", uriHolder.get().toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user