Browse Source

Fix @SubscribeMapping MESSAGE response destination

Prior to this commit, @SubscribeMapping mapped methods (backed with
@SendTo* annotations, or not) would send MESSAGEs with the wrong
destination. Instead of using the original SUBSCRIBE destination, it
would use the lookup path computed from the configured prefixes in the
application.

This commit fixes this issue - now @SubscribeMapping MESSAGEs use the
original SUBSCRIBE destination.

Issue: SPR-11648
pull/531/head
Brian Clozel 12 years ago
parent
commit
1c45d7573c
  1. 4
      spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java
  2. 1
      spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java
  3. 21
      spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandlerTests.java
  4. 28
      spring-websocket/src/test/java/org/springframework/web/socket/messaging/StompWebSocketIntegrationTests.java

4
spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java

@ -24,6 +24,7 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.messaging.Message; import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.core.MessagePostProcessor; import org.springframework.messaging.core.MessagePostProcessor;
import org.springframework.messaging.handler.DestinationPatternsMessageCondition;
import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler; import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor; import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
@ -158,7 +159,8 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
return value; return value;
} }
} }
return new String[] { defaultPrefix + inputHeaders.getDestination() }; return new String[] { defaultPrefix +
inputHeaders.getHeader(DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER) };
} }

1
spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java

@ -357,7 +357,6 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
String matchedPattern = mapping.getDestinationConditions().getPatterns().iterator().next(); String matchedPattern = mapping.getDestinationConditions().getPatterns().iterator().next();
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchedPattern, lookupDestination); Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchedPattern, lookupDestination);
headers.setDestination(lookupDestination);
headers.setHeader(DestinationVariableMethodArgumentResolver.DESTINATION_TEMPLATE_VARIABLES_HEADER, vars); headers.setHeader(DestinationVariableMethodArgumentResolver.DESTINATION_TEMPLATE_VARIABLES_HEADER, vars);
message = MessageBuilder.withPayload(message.getPayload()).setHeaders(headers).build(); message = MessageBuilder.withPayload(message.getPayload()).setHeaders(headers).build();

21
spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandlerTests.java

@ -32,6 +32,7 @@ import org.mockito.MockitoAnnotations;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.messaging.Message; import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.handler.DestinationPatternsMessageCondition;
import org.springframework.messaging.handler.annotation.SendTo; import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor; import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.messaging.simp.SimpMessagingTemplate;
@ -116,7 +117,7 @@ public class SendToMethodReturnValueHandlerTests {
when(this.messageChannel.send(any(Message.class))).thenReturn(true); when(this.messageChannel.send(any(Message.class))).thenReturn(true);
Message<?> inputMessage = createInputMessage("sess1", "sub1", "/dest", null); Message<?> inputMessage = createInputMessage("sess1", "sub1", "/app", "/dest", null);
this.handler.handleReturnValue(payloadContent, this.noAnnotationsReturnType, inputMessage); this.handler.handleReturnValue(payloadContent, this.noAnnotationsReturnType, inputMessage);
verify(this.messageChannel, times(1)).send(this.messageCaptor.capture()); verify(this.messageChannel, times(1)).send(this.messageCaptor.capture());
@ -134,7 +135,7 @@ public class SendToMethodReturnValueHandlerTests {
when(this.messageChannel.send(any(Message.class))).thenReturn(true); when(this.messageChannel.send(any(Message.class))).thenReturn(true);
String sessionId = "sess1"; String sessionId = "sess1";
Message<?> inputMessage = createInputMessage(sessionId, "sub1", null, null); Message<?> inputMessage = createInputMessage(sessionId, "sub1", null, null, null);
this.handler.handleReturnValue(payloadContent, this.sendToReturnType, inputMessage); this.handler.handleReturnValue(payloadContent, this.sendToReturnType, inputMessage);
verify(this.messageChannel, times(2)).send(this.messageCaptor.capture()); verify(this.messageChannel, times(2)).send(this.messageCaptor.capture());
@ -158,7 +159,7 @@ public class SendToMethodReturnValueHandlerTests {
when(this.messageChannel.send(any(Message.class))).thenReturn(true); when(this.messageChannel.send(any(Message.class))).thenReturn(true);
String sessionId = "sess1"; String sessionId = "sess1";
Message<?> inputMessage = createInputMessage(sessionId, "sub1", "/dest", null); Message<?> inputMessage = createInputMessage(sessionId, "sub1", "/app", "/dest", null);
this.handler.handleReturnValue(payloadContent, this.sendToDefaultDestReturnType, inputMessage); this.handler.handleReturnValue(payloadContent, this.sendToDefaultDestReturnType, inputMessage);
verify(this.messageChannel, times(1)).send(this.messageCaptor.capture()); verify(this.messageChannel, times(1)).send(this.messageCaptor.capture());
@ -177,7 +178,7 @@ public class SendToMethodReturnValueHandlerTests {
String sessionId = "sess1"; String sessionId = "sess1";
TestUser user = new TestUser(); TestUser user = new TestUser();
Message<?> inputMessage = createInputMessage(sessionId, "sub1", null, user); Message<?> inputMessage = createInputMessage(sessionId, "sub1", null, null, user);
this.handler.handleReturnValue(payloadContent, this.sendToUserReturnType, inputMessage); this.handler.handleReturnValue(payloadContent, this.sendToUserReturnType, inputMessage);
verify(this.messageChannel, times(2)).send(this.messageCaptor.capture()); verify(this.messageChannel, times(2)).send(this.messageCaptor.capture());
@ -202,7 +203,7 @@ public class SendToMethodReturnValueHandlerTests {
String sessionId = "sess1"; String sessionId = "sess1";
TestUser user = new UniqueUser(); TestUser user = new UniqueUser();
Message<?> inputMessage = createInputMessage(sessionId, "sub1", null, user); Message<?> inputMessage = createInputMessage(sessionId, "sub1", null, null, user);
this.handler.handleReturnValue(payloadContent, this.sendToUserReturnType, inputMessage); this.handler.handleReturnValue(payloadContent, this.sendToUserReturnType, inputMessage);
verify(this.messageChannel, times(2)).send(this.messageCaptor.capture()); verify(this.messageChannel, times(2)).send(this.messageCaptor.capture());
@ -221,7 +222,7 @@ public class SendToMethodReturnValueHandlerTests {
String sessionId = "sess1"; String sessionId = "sess1";
TestUser user = new TestUser(); TestUser user = new TestUser();
Message<?> inputMessage = createInputMessage(sessionId, "sub1", "/dest", user); Message<?> inputMessage = createInputMessage(sessionId, "sub1", "/app", "/dest", user);
this.handler.handleReturnValue(payloadContent, this.sendToUserDefaultDestReturnType, inputMessage); this.handler.handleReturnValue(payloadContent, this.sendToUserDefaultDestReturnType, inputMessage);
verify(this.messageChannel, times(1)).send(this.messageCaptor.capture()); verify(this.messageChannel, times(1)).send(this.messageCaptor.capture());
@ -234,12 +235,14 @@ public class SendToMethodReturnValueHandlerTests {
} }
private Message<?> createInputMessage(String sessId, String subsId, String destination, Principal principal) { private Message<?> createInputMessage(String sessId, String subsId, String destinationPrefix,
String destination, Principal principal) {
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(); SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create();
headers.setSessionId(sessId); headers.setSessionId(sessId);
headers.setSubscriptionId(subsId); headers.setSubscriptionId(subsId);
if (destination != null) { if (destination != null && destinationPrefix != null) {
headers.setDestination(destination); headers.setDestination(destinationPrefix + destination);
headers.setHeader(DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER, destination);
} }
if (principal != null) { if (principal != null) {
headers.setUser(principal); headers.setUser(principal);

28
spring-websocket/src/test/java/org/springframework/web/socket/messaging/StompWebSocketIntegrationTests.java

@ -36,6 +36,7 @@ import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.handler.annotation.MessageExceptionHandler; import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.simp.annotation.SubscribeMapping;
import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.simp.stomp.StompCommand; import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.support.AbstractSubscribableChannel; import org.springframework.messaging.support.AbstractSubscribableChannel;
@ -134,6 +135,28 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
} }
} }
// SPR-11648
@Test
public void sendSubscribeToControllerAndReceiveReply() throws Exception {
TextMessage message = create(StompCommand.SUBSCRIBE).headers(
"id:subs1", "destination:/app/number").build();
TestClientWebSocketHandler clientHandler = new TestClientWebSocketHandler(1, message);
WebSocketSession session = doHandshake(clientHandler, "/ws").get();
try {
assertTrue(clientHandler.latch.await(2, TimeUnit.SECONDS));
String payload = clientHandler.actual.get(0).getPayload();
assertTrue("Expected STOMP destination=/app/number, got " + payload, payload.contains("destination:/app/number"));
assertTrue("Expected STOMP Payload=42, got " + payload, payload.contains("42"));
}
finally {
session.close();
}
}
@IntegrationTestController @IntegrationTestController
static class SimpleController { static class SimpleController {
@ -164,6 +187,11 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
public int handle(int i) { public int handle(int i) {
return i + 1; return i + 1;
} }
@SubscribeMapping("/number")
public int number() {
return 42;
}
} }

Loading…
Cancel
Save