diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java index d5299ce09f..dd473a2621 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java @@ -151,9 +151,10 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH MessageHeaders headers = message.getHeaders(); String sessionId = SimpMessageHeaderAccessor.getSessionId(headers); PlaceholderResolver varResolver = initVarResolver(headers); - SendToUser sendToUser = getSendToUser(returnType); + Object annotation = findAnnotation(returnType); - if (sendToUser != null) { + if (annotation != null && annotation instanceof SendToUser) { + SendToUser sendToUser = (SendToUser) annotation; boolean broadcast = sendToUser.broadcast(); String user = getUserName(message, headers); if (user == null) { @@ -177,7 +178,7 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH } } else { - SendTo sendTo = getSendTo(returnType); + SendTo sendTo = (SendTo) annotation; String[] destinations = getTargetDestinations(sendTo, message, this.defaultDestinationPrefix); for (String destination : destinations) { destination = this.placeholderHelper.replacePlaceholders(destination, varResolver); @@ -186,6 +187,35 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH } } + private Object findAnnotation(MethodParameter returnType) { + Annotation[] annot = new Annotation[4]; + annot[0] = AnnotatedElementUtils.findMergedAnnotation(returnType.getMethod(), SendToUser.class); + annot[1] = AnnotatedElementUtils.findMergedAnnotation(returnType.getMethod(), SendTo.class); + annot[2] = AnnotatedElementUtils.findMergedAnnotation(returnType.getDeclaringClass(), SendToUser.class); + annot[3] = AnnotatedElementUtils.findMergedAnnotation(returnType.getDeclaringClass(), SendTo.class); + + if (annot[0] != null && !ObjectUtils.isEmpty(((SendToUser) annot[0]).value())) { + return annot[0]; + } + if (annot[1] != null && !ObjectUtils.isEmpty(((SendTo) annot[1]).value())) { + return annot[1]; + } + if (annot[2] != null && !ObjectUtils.isEmpty(((SendToUser) annot[2]).value())) { + return annot[2]; + } + if (annot[3] != null && !ObjectUtils.isEmpty(((SendTo) annot[3]).value())) { + return annot[3]; + } + + for (int i=0; i < 4; i++) { + if (annot[i] != null) { + return annot[i]; + } + } + + return null; + } + private SendToUser getSendToUser(MethodParameter returnType) { SendToUser annot = AnnotatedElementUtils.findMergedAnnotation(returnType.getMethod(), SendToUser.class); if (annot != null && !ObjectUtils.isEmpty(annot.value())) { diff --git a/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandlerTests.java b/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandlerTests.java index af573a7df6..5d831dcaf5 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandlerTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandlerTests.java @@ -287,6 +287,39 @@ public class SendToMethodReturnValueHandlerTests { assertResponse(this.userDefaultOverrideAnnotation, sessionId, 1, "/user/sess1/dest4"); } + @Test // SPR-14238 + public void sendToUserWithSendToDefaultOverride() throws Exception { + given(this.messageChannel.send(any(Message.class))).willReturn(true); + + Class clazz = SendToUserWithSendToOverrideTestBean.class; + Method method = clazz.getDeclaredMethod("handleAndSendToDefaultDestination"); + MethodParameter parameter = new SynthesizingMethodParameter(method, -1); + + String sessionId = "sess1"; + Message inputMessage = createMessage(sessionId, "sub1", null, null, null); + this.handler.handleReturnValue(PAYLOAD, parameter, inputMessage); + + verify(this.messageChannel, times(1)).send(this.messageCaptor.capture()); + assertResponse(parameter, sessionId, 0, "/user/sess1/dest-default"); + } + + @Test // SPR-14238 + public void sendToUserWithSendToOverride() throws Exception { + given(this.messageChannel.send(any(Message.class))).willReturn(true); + + Class clazz = SendToUserWithSendToOverrideTestBean.class; + Method method = clazz.getDeclaredMethod("handleAndSendToOverride"); + MethodParameter parameter = new SynthesizingMethodParameter(method, -1); + + String sessionId = "sess1"; + Message inputMessage = createMessage(sessionId, "sub1", null, null, null); + this.handler.handleReturnValue(PAYLOAD, parameter, inputMessage); + + verify(this.messageChannel, times(2)).send(this.messageCaptor.capture()); + assertResponse(parameter, sessionId, 0, "/dest3"); + assertResponse(parameter, sessionId, 1, "/dest4"); + } + private void assertResponse(MethodParameter methodParameter, String sessionId, int index, String destination) { @@ -552,7 +585,7 @@ public class SendToMethodReturnValueHandlerTests { @SendTo @Retention(RetentionPolicy.RUNTIME) - public @interface MySendTo { + @interface MySendTo { @AliasFor(annotation = SendTo.class, attribute = "value") String[] dest(); @@ -560,7 +593,7 @@ public class SendToMethodReturnValueHandlerTests { @SendToUser @Retention(RetentionPolicy.RUNTIME) - public @interface MySendToUser { + @interface MySendToUser { @AliasFor(annotation = SendToUser.class, attribute = "destinations") String[] dest(); @@ -568,47 +601,47 @@ public class SendToMethodReturnValueHandlerTests { @SuppressWarnings("unused") - public String handleNoAnnotations() { + String handleNoAnnotations() { return PAYLOAD; } @SendTo @SuppressWarnings("unused") - public String handleAndSendToDefaultDestination() { + String handleAndSendToDefaultDestination() { return PAYLOAD; } @SendTo({"/dest1", "/dest2"}) @SuppressWarnings("unused") - public String handleAndSendTo() { + String handleAndSendTo() { return PAYLOAD; } @SendTo("/topic/chat.message.filtered.{roomName}") @SuppressWarnings("unused") - public String handleAndSendToWithPlaceholders() { + String handleAndSendToWithPlaceholders() { return PAYLOAD; } @SendToUser @SuppressWarnings("unused") - public String handleAndSendToUserDefaultDestination() { + String handleAndSendToUserDefaultDestination() { return PAYLOAD; } @SendToUser(broadcast = false) @SuppressWarnings("unused") - public String handleAndSendToUserDefaultDestinationSingleSession() { + String handleAndSendToUserDefaultDestinationSingleSession() { return PAYLOAD; } @SendToUser({"/dest1", "/dest2"}) @SuppressWarnings("unused") - public String handleAndSendToUser() { + String handleAndSendToUser() { return PAYLOAD; } @SendToUser(destinations = { "/dest1", "/dest2" }, broadcast = false) @SuppressWarnings("unused") - public String handleAndSendToUserSingleSession() { + String handleAndSendToUserSingleSession() { return PAYLOAD; } @JsonView(MyJacksonView1.class) @SuppressWarnings("unused") - public JacksonViewBean handleAndSendToJsonView() { + JacksonViewBean handleAndSendToJsonView() { JacksonViewBean payload = new JacksonViewBean(); payload.setWithView1("with"); payload.setWithView2("with"); @@ -620,17 +653,17 @@ public class SendToMethodReturnValueHandlerTests { @MySendTo(dest = "/dest-default") @SuppressWarnings("unused") private static class SendToTestBean { - public String handleNoAnnotation() { + String handleNoAnnotation() { return PAYLOAD; } @SendTo - public String handleAndSendToDefaultDestination() { + String handleAndSendToDefaultDestination() { return PAYLOAD; } @MySendTo(dest = {"/dest3", "/dest4"}) - public String handleAndSendToOverride() { + String handleAndSendToOverride() { return PAYLOAD; } } @@ -638,17 +671,31 @@ public class SendToMethodReturnValueHandlerTests { @MySendToUser(dest = "/dest-default") @SuppressWarnings("unused") private static class SendToUserTestBean { - public String handleNoAnnotation() { + String handleNoAnnotation() { return PAYLOAD; } @SendToUser - public String handleAndSendToDefaultDestination() { + String handleAndSendToDefaultDestination() { return PAYLOAD; } @MySendToUser(dest = {"/dest3", "/dest4"}) - public String handleAndSendToOverride() { + String handleAndSendToOverride() { + return PAYLOAD; + } + } + + @MySendToUser(dest = "/dest-default") @SuppressWarnings("unused") + private static class SendToUserWithSendToOverrideTestBean { + + @SendTo + String handleAndSendToDefaultDestination() { + return PAYLOAD; + } + + @MySendTo(dest = {"/dest3", "/dest4"}) + String handleAndSendToOverride() { return PAYLOAD; } } @@ -672,23 +719,23 @@ public class SendToMethodReturnValueHandlerTests { return withView1; } - public void setWithView1(String withView1) { + void setWithView1(String withView1) { this.withView1 = withView1; } - public String getWithView2() { + String getWithView2() { return withView2; } - public void setWithView2(String withView2) { + void setWithView2(String withView2) { this.withView2 = withView2; } - public String getWithoutView() { + String getWithoutView() { return withoutView; } - public void setWithoutView(String withoutView) { + void setWithoutView(String withoutView) { this.withoutView = withoutView; } }