From 5ba036d679d1894ed3fc870a9b9b5202a65bc6e2 Mon Sep 17 00:00:00 2001 From: Gary Russell Date: Wed, 16 Oct 2019 10:33:09 -0400 Subject: [PATCH] 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** --- .../support/MessagingMethodInvokerHelper.java | 4 ++++ .../MethodInvokingMessageProcessorTests.java | 18 ++++++++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java index 2c240af5054..e663d76167c 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/handler/support/MessagingMethodInvokerHelper.java @@ -1280,9 +1280,13 @@ private String determineHeaderExpression(Annotation headerAnnotation, MethodPara 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]; diff --git a/spring-integration-core/src/test/java/org/springframework/integration/handler/MethodInvokingMessageProcessorTests.java b/spring-integration-core/src/test/java/org/springframework/integration/handler/MethodInvokingMessageProcessorTests.java index e66a5f1a4a7..9d455647e17 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/handler/MethodInvokingMessageProcessorTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/handler/MethodInvokingMessageProcessorTests.java @@ -157,6 +157,7 @@ public Person(String fname, String lname) { this.name = fname + " " + lname; } + @Override public String toString() { return "Person: " + this.name; } @@ -544,7 +545,8 @@ private void optionalAndRequiredWithAnnotatedMethodGuts(MethodInvokingMessagePro @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 void optionalAndRequiredDottedWithAnnotatedMethod() throws Exception { @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 @@ private void optionalAndRequiredDottedWithAnnotatedMethodGuts(MethodInvokingMess processor.setBeanFactory(mock(BeanFactory.class)); Message 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 String optionalAndRequiredHeader(@Header(required = false) String prop, } 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) {