INT-4217: SpEL Compilable for Required Header Args
JIRA: https://jira.spring.io/browse/INT-4217 Previously, SpEL method calls with required header parameters had the following form: #target.messageAndHeader(message, headers['number'] != null ? headers['number'] : T(org.springframework.util.Assert).isTrue(false, 'required header not available: number')) The SpEL compiler cannot compile this because the else clause of the ternary has no `exitDescriptor` to indicate the type. Change the expression to use a function for required headers. Also use an Elvis operator when possible. Some examples of new expressions: #target.optionalAndRequiredHeader(headers['prop'] ?: null, #requiredHeader(headers, 'num')) #target.optionalAndRequiredDottedHeader(headers['dot1'] != null ? headers['dot1'].foo : null, #requiredHeader(headers, 'dot2').baz In the second case, we can't use an Elvis because we're accessing a `foo` property of the header. __cherry-pick to 4.3.x__ - make `ParametersWrapper` `static` - minor conflicts in imports - remove the perf test * Polishing: remove redundant annotation args for their default values usage
This commit is contained in:
committed by
Artem Bilan
parent
1f9d07ae24
commit
c5c874f563
@@ -31,6 +31,7 @@ import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -314,7 +315,7 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
this.displayString = sb.toString() + "]";
|
||||
}
|
||||
|
||||
private void prepareEvaluationContext() {
|
||||
private void prepareEvaluationContext() throws Exception {
|
||||
StandardEvaluationContext context = getEvaluationContext(false);
|
||||
Class<?> targetType = AopUtils.getTargetClass(this.targetObject);
|
||||
if (this.method != null) {
|
||||
@@ -333,6 +334,8 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
context.registerMethodFilter(targetType, filter);
|
||||
}
|
||||
context.setVariable("target", this.targetObject);
|
||||
context.registerFunction("requiredHeader", ParametersWrapper.class.getDeclaredMethod("getHeader",
|
||||
Map.class, String.class));
|
||||
}
|
||||
|
||||
private boolean canReturnExpectedType(AnnotatedMethodFilter filter, Class<?> targetType,
|
||||
@@ -949,12 +952,16 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
+ "disabled or header name is not explicitly provided via @Header annotation.");
|
||||
String headerRetrievalExpression = "headers['" + headerName + "']";
|
||||
String fullHeaderExpression = headerRetrievalExpression + relativeExpression;
|
||||
String fallbackExpression = (annotationAttributes.getBoolean("required")
|
||||
&& !methodParameter.getParameterType().getName().equals("java.util.Optional"))
|
||||
? "T(org.springframework.util.Assert).isTrue(false, 'required header not available: "
|
||||
+ headerName + "')"
|
||||
: "null";
|
||||
return headerRetrievalExpression + " != null ? " + fullHeaderExpression + " : " + fallbackExpression;
|
||||
if (annotationAttributes.getBoolean("required")
|
||||
&& !methodParameter.getParameterType().equals(Optional.class)) {
|
||||
return "#requiredHeader(headers, '" + headerName + "')" + relativeExpression;
|
||||
}
|
||||
else if (!StringUtils.hasLength(relativeExpression)) {
|
||||
return headerRetrievalExpression + " ?: null";
|
||||
}
|
||||
else {
|
||||
return headerRetrievalExpression + " != null ? " + fullHeaderExpression + " : null";
|
||||
}
|
||||
}
|
||||
|
||||
private void setExclusiveTargetParameterType(TypeDescriptor targetParameterType,
|
||||
@@ -999,6 +1006,21 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
this.message = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* SpEL Function to retrieve a required header.
|
||||
* @param headers the headers.
|
||||
* @param header the header name
|
||||
* @return the header
|
||||
* @throws IllegalArgumentException if the header does not exist
|
||||
*/
|
||||
public static Object getHeader(Map<?, ?> headers, String header) {
|
||||
Object object = headers.get(header);
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException("required header not available: " + header);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
public Object getPayload() {
|
||||
Assert.state(this.payload != null,
|
||||
"Invalid method parameter for payload: was expecting collection.");
|
||||
|
||||
Reference in New Issue
Block a user