diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionEvalMap.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionEvalMap.java
index 0ffb5cfcca1..57453d9acc5 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionEvalMap.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/ExpressionEvalMap.java
@@ -47,13 +47,13 @@
*
* {@code
*ExpressionEvalMap evalMap = ExpressionEvalMap
- * .from(expressions)
- * .usingCallback(new EvaluationCallback() {
- * Object evaluate(Expression expression) {
- * // return some expression evaluation
- * }
- * })
- * .build();
+ * .from(expressions)
+ * .usingCallback(new EvaluationCallback() {
+ * Object evaluate(Expression expression) {
+ * // return some expression evaluation
+ * }
+ * })
+ * .build();
*}
*
*
@@ -84,6 +84,7 @@ private ExpressionEvalMap(Map original, EvaluationCallback evaluation
* from {@link #original} and returns the result of evaluation using {@link #evaluationCallback}.
*/
@Override
+ @Nullable
public Object get(Object key) {
Object value = this.original.get(key);
if (value != null) {
@@ -106,9 +107,9 @@ else if (value instanceof String) {
@Override
public Set> entrySet() {
- return this.original.entrySet()
+ return this.original.keySet()
.stream()
- .map(e -> new SimpleImmutableEntry<>(e.getKey(), get(e.getKey())))
+ .map((key) -> new SimpleImmutableEntry<>(key, get(key)))
.collect(Collectors.toSet());
}
@@ -206,22 +207,35 @@ public interface EvaluationCallback {
*/
public static class ComponentsEvaluationCallback implements EvaluationCallback {
+ @Nullable
private final EvaluationContext context;
+ @Nullable
private final Object root;
+ private final boolean rootExplicitlySet;
+
+ @Nullable
private final Class> returnType;
- public ComponentsEvaluationCallback(EvaluationContext context, Object root, Class> returnType) {
+ public ComponentsEvaluationCallback(@Nullable EvaluationContext context, @Nullable Object root,
+ boolean rootExplicitlySet, @Nullable Class> returnType) {
+
this.context = context;
this.root = root;
+ this.rootExplicitlySet = rootExplicitlySet;
this.returnType = returnType;
}
@Override
public Object evaluate(Expression expression) {
if (this.context != null) {
- return expression.getValue(this.context, this.root, this.returnType);
+ if (this.rootExplicitlySet) {
+ return expression.getValue(this.context, this.root, this.returnType);
+ }
+ else {
+ return expression.getValue(this.context, this.returnType);
+ }
}
return expression.getValue(this.root, this.returnType);
}
@@ -238,10 +252,15 @@ public static final class ExpressionEvalMapBuilder {
private EvaluationCallback evaluationCallback;
+ @Nullable
private EvaluationContext context;
+ @Nullable
private Object root;
+ private boolean rootExplicitlySet;
+
+ @Nullable
private Class> returnType;
private final ExpressionEvalMapComponentsBuilder evalMapComponentsBuilder =
@@ -267,8 +286,9 @@ public ExpressionEvalMapComponentsBuilder usingEvaluationContext(EvaluationConte
return this.evalMapComponentsBuilder;
}
- public ExpressionEvalMapComponentsBuilder withRoot(Object root) {
+ public ExpressionEvalMapComponentsBuilder withRoot(@Nullable Object root) {
this.root = root;
+ this.rootExplicitlySet = true;
return this.evalMapComponentsBuilder;
}
@@ -295,7 +315,8 @@ public ExpressionEvalMap build() {
else {
return new ExpressionEvalMap(ExpressionEvalMapBuilder.this.expressions,
new ComponentsEvaluationCallback(ExpressionEvalMapBuilder.this.context,
- ExpressionEvalMapBuilder.this.root, ExpressionEvalMapBuilder.this.returnType));
+ ExpressionEvalMapBuilder.this.root, ExpressionEvalMapBuilder.this.rootExplicitlySet,
+ ExpressionEvalMapBuilder.this.returnType));
}
}
@@ -315,7 +336,7 @@ public ExpressionEvalMapComponentsBuilder usingEvaluationContext(EvaluationConte
}
@Override
- public ExpressionEvalMapComponentsBuilder withRoot(Object root) {
+ public ExpressionEvalMapComponentsBuilder withRoot(@Nullable Object root) {
return ExpressionEvalMapBuilder.this.withRoot(root);
}
@@ -340,7 +361,7 @@ public interface ExpressionEvalMapComponentsBuilder extends ExpressionEvalMapFin
ExpressionEvalMapComponentsBuilder usingEvaluationContext(EvaluationContext context);
- ExpressionEvalMapComponentsBuilder withRoot(Object root);
+ ExpressionEvalMapComponentsBuilder withRoot(@Nullable Object root);
ExpressionEvalMapComponentsBuilder withReturnType(Class> returnType);
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/expression/FunctionExpression.java b/spring-integration-core/src/main/java/org/springframework/integration/expression/FunctionExpression.java
index a3ba3be7668..e608d7259b8 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/expression/FunctionExpression.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/expression/FunctionExpression.java
@@ -25,6 +25,7 @@
import org.springframework.expression.TypedValue;
import org.springframework.expression.common.ExpressionUtils;
import org.springframework.expression.spel.support.StandardEvaluationContext;
+import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -47,6 +48,7 @@
*
* @author Artem Bilan
* @author Gary Russell
+ *
* @since 5.0
*/
public class FunctionExpression implements Expression {
@@ -65,46 +67,58 @@ public FunctionExpression(Function function) {
}
@Override
+ @Nullable
public Object getValue() throws EvaluationException {
return this.function.apply(null);
}
@Override
+ @Nullable
@SuppressWarnings("unchecked")
- public Object getValue(Object rootObject) throws EvaluationException {
+ public Object getValue(@Nullable Object rootObject) throws EvaluationException {
return this.function.apply((S) rootObject);
}
@Override
- public T getValue(Class desiredResultType) throws EvaluationException {
+ @Nullable
+ public T getValue(@Nullable Class desiredResultType) throws EvaluationException {
return getValue(this.defaultContext, desiredResultType);
}
@Override
- public T getValue(Object rootObject, Class desiredResultType) throws EvaluationException {
+ @Nullable
+ public T getValue(@Nullable Object rootObject, @Nullable Class desiredResultType)
+ throws EvaluationException {
+
return getValue(this.defaultContext, rootObject, desiredResultType);
}
@Override
+ @Nullable
public Object getValue(EvaluationContext context) throws EvaluationException {
- Object root = context.getRootObject().getValue();
- return root == null ? getValue() : getValue(root);
+ return getValue(context.getRootObject().getValue());
}
@Override
- public Object getValue(EvaluationContext context, Object rootObject) throws EvaluationException {
+ @Nullable
+ public Object getValue(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException {
return getValue(rootObject);
}
@Override
- public T getValue(EvaluationContext context, Class desiredResultType) throws EvaluationException {
+ @Nullable
+ public T getValue(EvaluationContext context, @Nullable Class desiredResultType) throws EvaluationException {
return ExpressionUtils.convertTypedValue(context, new TypedValue(getValue(context)), desiredResultType);
}
@Override
- public T getValue(EvaluationContext context, Object rootObject, Class desiredResultType)
+ @Nullable
+ public T getValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Class desiredResultType)
throws EvaluationException {
- return ExpressionUtils.convertTypedValue(context, new TypedValue(getValue(rootObject)), desiredResultType);
+
+ return ExpressionUtils.convertTypedValue(context,
+ new TypedValue(getValue(context, rootObject)),
+ desiredResultType);
}
@Override
@@ -113,7 +127,7 @@ public Class> getValueType() throws EvaluationException {
}
@Override
- public Class> getValueType(Object rootObject) throws EvaluationException {
+ public Class> getValueType(@Nullable Object rootObject) throws EvaluationException {
throw this.readOnlyException;
}
@@ -123,7 +137,7 @@ public Class> getValueType(EvaluationContext context) throws EvaluationExcepti
}
@Override
- public Class> getValueType(EvaluationContext context, Object rootObject) throws EvaluationException {
+ public Class> getValueType(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException {
throw this.readOnlyException;
}
@@ -133,7 +147,7 @@ public TypeDescriptor getValueTypeDescriptor() throws EvaluationException {
}
@Override
- public TypeDescriptor getValueTypeDescriptor(Object rootObject) throws EvaluationException {
+ public TypeDescriptor getValueTypeDescriptor(@Nullable Object rootObject) throws EvaluationException {
throw this.readOnlyException;
}
@@ -143,23 +157,25 @@ public TypeDescriptor getValueTypeDescriptor(EvaluationContext context) throws E
}
@Override
- public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, Object rootObject)
+ public TypeDescriptor getValueTypeDescriptor(EvaluationContext context, @Nullable Object rootObject)
throws EvaluationException {
throw this.readOnlyException;
}
@Override
- public void setValue(EvaluationContext context, Object value) throws EvaluationException {
+ public void setValue(EvaluationContext context, @Nullable Object value) throws EvaluationException {
throw this.readOnlyException;
}
@Override
- public void setValue(Object rootObject, Object value) throws EvaluationException {
+ public void setValue(@Nullable Object rootObject, @Nullable Object value) throws EvaluationException {
throw this.readOnlyException;
}
@Override
- public void setValue(EvaluationContext context, Object rootObject, Object value) throws EvaluationException {
+ public void setValue(EvaluationContext context, @Nullable Object rootObject, @Nullable Object value)
+ throws EvaluationException {
+
throw this.readOnlyException;
}
@@ -169,12 +185,12 @@ public boolean isWritable(EvaluationContext context) throws EvaluationException
}
@Override
- public boolean isWritable(EvaluationContext context, Object rootObject) throws EvaluationException {
+ public boolean isWritable(EvaluationContext context, @Nullable Object rootObject) throws EvaluationException {
return false;
}
@Override
- public boolean isWritable(Object rootObject) throws EvaluationException {
+ public boolean isWritable(@Nullable Object rootObject) throws EvaluationException {
return false;
}
diff --git a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingEndpointSupport.java b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingEndpointSupport.java
index a9de5dc5394..1755278a872 100644
--- a/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingEndpointSupport.java
+++ b/spring-integration-http/src/main/java/org/springframework/integration/http/inbound/HttpRequestHandlingEndpointSupport.java
@@ -276,6 +276,7 @@ private Message> actualDoHandleRequest(HttpServletRequest servletRequest, Requ
headers.putAll(
ExpressionEvalMap.from(getHeaderExpressions())
.usingEvaluationContext(evaluationContext)
+ .withRoot(httpEntity)
.build());
}
diff --git a/spring-integration-http/src/test/java/org/springframework/integration/http/dsl/HttpDslTests.java b/spring-integration-http/src/test/java/org/springframework/integration/http/dsl/HttpDslTests.java
index 95b693fb4c5..545b70fa83d 100644
--- a/spring-integration-http/src/test/java/org/springframework/integration/http/dsl/HttpDslTests.java
+++ b/spring-integration-http/src/test/java/org/springframework/integration/http/dsl/HttpDslTests.java
@@ -181,8 +181,9 @@ public void testMultiPartFiles() throws Exception {
Message> result = this.multiPartFilesChannel.receive(10_000);
+ assertThat(result).isNotNull();
+ assertThat(result.getHeaders()).containsEntry("contentLength", -1L);
assertThat(result)
- .isNotNull()
.extracting(Message::getPayload)
.satisfies((payload) ->
assertThat((Map) payload)
@@ -321,7 +322,8 @@ public IntegrationFlow httpProxyErrorFlow() {
@Bean
public IntegrationFlow multiPartFilesFlow() {
return IntegrationFlows
- .from(Http.inboundChannelAdapter("/multiPartFiles"))
+ .from(Http.inboundChannelAdapter("/multiPartFiles")
+ .headerFunction("contentLength", (entity) -> entity.getHeaders().getContentLength()))
.channel((c) -> c.queue("multiPartFilesChannel"))
.get();
}
diff --git a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/inbound/WebFluxInboundEndpoint.java b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/inbound/WebFluxInboundEndpoint.java
index 8e02c488879..3dcb5475a52 100644
--- a/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/inbound/WebFluxInboundEndpoint.java
+++ b/spring-integration-webflux/src/main/java/org/springframework/integration/webflux/inbound/WebFluxInboundEndpoint.java
@@ -268,6 +268,7 @@ private Mono, RequestEntity>>> buildMessage(RequestEnti
headers.putAll(
ExpressionEvalMap.from(getHeaderExpressions())
.usingEvaluationContext(evaluationContext)
+ .withRoot(httpEntity)
.build());
}