GH-3083: Support @Header with dotted literals

Fixes https://github.com/spring-projects/spring-integration/issues/3083

`@Header("foo.bar")` means extract property `bar` from header `foo`.

Support `@Header("'foo.bar'")`, meaning get the value of header `foo.bar`.

**cherry-pick to 5.1.x, 4.3.x**
This commit is contained in:
Gary Russell
2019-10-16 10:33:09 -04:00
committed by Artem Bilan
parent 911cdc86b5
commit 87af95ee7a
2 changed files with 16 additions and 6 deletions

View File

@@ -1280,9 +1280,13 @@ public class MessagingMethodInvokerHelper extends AbstractExpressionEvaluator im
AnnotationAttributes annotationAttributes =
(AnnotationAttributes) AnnotationUtils.getAnnotationAttributes(headerAnnotation);
String valueAttribute = annotationAttributes.getString(AnnotationUtils.VALUE);
int len = valueAttribute == null ? 0 : valueAttribute.length();
if (!StringUtils.hasText(valueAttribute)) {
headerName = methodParameter.getParameterName();
}
else if (len > 2 && valueAttribute.charAt(0) == '\'' && valueAttribute.charAt(len - 1) == '\'') {
headerName = valueAttribute.substring(1, len - 1);
}
else if (valueAttribute.indexOf('.') != -1) {
String[] tokens = valueAttribute.split("\\.", 2);
headerName = tokens[0];

View File

@@ -157,6 +157,7 @@ public class MethodInvokingMessageProcessorTests {
this.name = fname + " " + lname;
}
@Override
public String toString() {
return "Person: " + this.name;
}
@@ -544,7 +545,8 @@ public class MethodInvokingMessageProcessorTests {
@Test
public void optionalAndRequiredDottedWithAnnotatedMethod() throws Exception {
AnnotatedTestService service = new AnnotatedTestService();
Method method = service.getClass().getMethod("optionalAndRequiredDottedHeader", String.class, Integer.class);
Method method = service.getClass().getMethod("optionalAndRequiredDottedHeader", String.class, Integer.class,
String.class);
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(service, method);
processor.setUseSpelInvoker(true);
optionalAndRequiredDottedWithAnnotatedMethodGuts(processor, false);
@@ -553,7 +555,8 @@ public class MethodInvokingMessageProcessorTests {
@Test
public void compiledOptionalAndRequiredDottedWithAnnotatedMethod() throws Exception {
AnnotatedTestService service = new AnnotatedTestService();
Method method = service.getClass().getMethod("optionalAndRequiredDottedHeader", String.class, Integer.class);
Method method = service.getClass().getMethod("optionalAndRequiredDottedHeader", String.class, Integer.class,
String.class);
MethodInvokingMessageProcessor processor = new MethodInvokingMessageProcessor(service, method);
processor.setUseSpelInvoker(true);
DirectFieldAccessor compilerConfigAccessor = compileImmediate(processor);
@@ -569,17 +572,20 @@ public class MethodInvokingMessageProcessorTests {
processor.setBeanFactory(mock(BeanFactory.class));
Message<String> message = MessageBuilder.withPayload("hello")
.setHeader("dot2", new DotBean())
.setHeader("dotted.literal", "dotted")
.build();
Object result = processor.processMessage(message);
assertThat(result).isEqualTo("null42");
assertThat(result).isEqualTo("null42dotted");
message = MessageBuilder.withPayload("hello")
.setHeader("dot1", new DotBean())
.setHeader("dot2", new DotBean())
.setHeader("dotted.literal", "dotted")
.build();
result = processor.processMessage(message);
assertThat(result).isEqualTo("bar42");
assertThat(result).isEqualTo("bar42dotted");
message = MessageBuilder.withPayload("hello")
.setHeader("dot1", new DotBean())
.setHeader("dotted.literal", "dotted")
.build();
try {
result = processor.processMessage(message);
@@ -1345,8 +1351,8 @@ public class MethodInvokingMessageProcessorTests {
}
public String optionalAndRequiredDottedHeader(@Header(name = "dot1.foo", required = false) String prop,
@Header(name = "dot2.baz") Integer num) {
return prop + num;
@Header(name = "dot2.baz") Integer num, @Header("'dotted.literal'") String dotted) {
return prop + num + dotted;
}
public Properties propertiesMethod(Properties properties) {