Browse Source

@SendToUser supported on the class level

Issue: SPR-12047
pull/959/head
Rossen Stoyanchev 10 years ago
parent
commit
03e3ef53ab
  1. 7
      spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/SendToUser.java
  2. 17
      spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandler.java
  3. 83
      spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SendToMethodReturnValueHandlerTests.java
  4. 3
      src/asciidoc/web-websocket.adoc
  5. 2
      src/asciidoc/whats-new.adoc

7
spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/SendToUser.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -30,6 +30,9 @@ import org.springframework.core.annotation.AliasFor; @@ -30,6 +30,9 @@ import org.springframework.core.annotation.AliasFor;
* destination(s) prepended with <code>"/user/{username}"</code> where the user name
* is extracted from the headers of the input message being handled.
*
* <p>The annotation may also be placed at class-level in which case all methods
* in the class where the annotation applies will inherit it.
* @author Rossen Stoyanchev
* @author Sam Brannen
* @since 4.0
@ -37,7 +40,7 @@ import org.springframework.core.annotation.AliasFor; @@ -37,7 +40,7 @@ import org.springframework.core.annotation.AliasFor;
* @see org.springframework.messaging.simp.user.UserDestinationMessageHandler
* @see org.springframework.messaging.simp.SimpMessageHeaderAccessor#getUser()
*/
@Target(ElementType.METHOD)
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SendToUser {

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

@ -134,7 +134,8 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH @@ -134,7 +134,8 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
public boolean supportsReturnType(MethodParameter returnType) {
if (returnType.getMethodAnnotation(SendTo.class) != null ||
AnnotationUtils.getAnnotation(returnType.getDeclaringClass(), SendTo.class) != null ||
returnType.getMethodAnnotation(SendToUser.class) != null) {
returnType.getMethodAnnotation(SendToUser.class) != null ||
AnnotationUtils.getAnnotation(returnType.getDeclaringClass(), SendToUser.class) != null) {
return true;
}
return (!this.annotationRequired);
@ -149,7 +150,7 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH @@ -149,7 +150,7 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
MessageHeaders headers = message.getHeaders();
String sessionId = SimpMessageHeaderAccessor.getSessionId(headers);
PlaceholderResolver varResolver = initVarResolver(headers);
SendToUser sendToUser = returnType.getMethodAnnotation(SendToUser.class);
SendToUser sendToUser = getSendToUser(returnType);
if (sendToUser != null) {
boolean broadcast = sendToUser.broadcast();
@ -184,6 +185,18 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH @@ -184,6 +185,18 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
}
}
private SendToUser getSendToUser(MethodParameter returnType) {
SendToUser annot = returnType.getMethodAnnotation(SendToUser.class);
if (annot != null && !ObjectUtils.isEmpty((annot.value()))) {
return annot;
}
SendToUser typeAnnot = AnnotationUtils.getAnnotation(returnType.getDeclaringClass(), SendToUser.class);
if (typeAnnot != null && !ObjectUtils.isEmpty((typeAnnot.value()))) {
return typeAnnot;
}
return (annot != null ? annot : typeAnnot);
}
private SendTo getSendTo(MethodParameter returnType) {
SendTo sendTo = returnType.getMethodAnnotation(SendTo.class);
if (sendTo != null && !ObjectUtils.isEmpty((sendTo.value()))) {

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

@ -91,6 +91,9 @@ public class SendToMethodReturnValueHandlerTests { @@ -91,6 +91,9 @@ public class SendToMethodReturnValueHandlerTests {
private MethodParameter defaultNoAnnotation;
private MethodParameter defaultEmptyAnnotation;
private MethodParameter defaultOverrideAnnotation;
private MethodParameter userDefaultNoAnnotation;
private MethodParameter userDefaultEmptyAnnotation;
private MethodParameter userDefaultOverrideAnnotation;
@Before
@ -133,14 +136,23 @@ public class SendToMethodReturnValueHandlerTests { @@ -133,14 +136,23 @@ public class SendToMethodReturnValueHandlerTests {
method = this.getClass().getDeclaredMethod("handleAndSendToJsonView");
this.jsonViewReturnType = new SynthesizingMethodParameter(method, -1);
method = TestBean.class.getDeclaredMethod("handleNoAnnotation");
method = SendToTestBean.class.getDeclaredMethod("handleNoAnnotation");
this.defaultNoAnnotation = new SynthesizingMethodParameter(method, -1);
method = TestBean.class.getDeclaredMethod("handleAndSendToDefaultDestination");
method = SendToTestBean.class.getDeclaredMethod("handleAndSendToDefaultDestination");
this.defaultEmptyAnnotation = new SynthesizingMethodParameter(method, -1);
method = TestBean.class.getDeclaredMethod("handleAndSendToOverride");
method = SendToTestBean.class.getDeclaredMethod("handleAndSendToOverride");
this.defaultOverrideAnnotation = new SynthesizingMethodParameter(method, -1);
method = SendToUserTestBean.class.getDeclaredMethod("handleNoAnnotation");
this.userDefaultNoAnnotation = new SynthesizingMethodParameter(method, -1);
method = SendToUserTestBean.class.getDeclaredMethod("handleAndSendToDefaultDestination");
this.userDefaultEmptyAnnotation = new SynthesizingMethodParameter(method, -1);
method = SendToUserTestBean.class.getDeclaredMethod("handleAndSendToOverride");
this.userDefaultOverrideAnnotation = new SynthesizingMethodParameter(method, -1);
}
@ -154,6 +166,10 @@ public class SendToMethodReturnValueHandlerTests { @@ -154,6 +166,10 @@ public class SendToMethodReturnValueHandlerTests {
assertTrue(this.handler.supportsReturnType(this.defaultNoAnnotation));
assertTrue(this.handler.supportsReturnType(this.defaultEmptyAnnotation));
assertTrue(this.handler.supportsReturnType(this.defaultOverrideAnnotation));
assertTrue(this.handler.supportsReturnType(this.userDefaultNoAnnotation));
assertTrue(this.handler.supportsReturnType(this.userDefaultEmptyAnnotation));
assertTrue(this.handler.supportsReturnType(this.userDefaultOverrideAnnotation));
}
@Test
@ -230,6 +246,44 @@ public class SendToMethodReturnValueHandlerTests { @@ -230,6 +246,44 @@ public class SendToMethodReturnValueHandlerTests {
assertResponse(this.defaultOverrideAnnotation, sessionId, 1, "/dest4");
}
@Test
public void sendToUserClassDefaultNoAnnotation() throws Exception {
given(this.messageChannel.send(any(Message.class))).willReturn(true);
String sessionId = "sess1";
Message<?> inputMessage = createInputMessage(sessionId, "sub1", null, null, null);
this.handler.handleReturnValue(PAYLOAD, this.userDefaultNoAnnotation, inputMessage);
verify(this.messageChannel, times(1)).send(this.messageCaptor.capture());
assertResponse(this.userDefaultNoAnnotation, sessionId, 0, "/user/sess1/dest-default");
}
@Test
public void sendToUserClassDefaultEmptyAnnotation() throws Exception {
given(this.messageChannel.send(any(Message.class))).willReturn(true);
String sessionId = "sess1";
Message<?> inputMessage = createInputMessage(sessionId, "sub1", null, null, null);
this.handler.handleReturnValue(PAYLOAD, this.userDefaultEmptyAnnotation, inputMessage);
verify(this.messageChannel, times(1)).send(this.messageCaptor.capture());
assertResponse(this.userDefaultEmptyAnnotation, sessionId, 0, "/user/sess1/dest-default");
}
@Test
public void sendToUserClassDefaultOverride() throws Exception {
given(this.messageChannel.send(any(Message.class))).willReturn(true);
String sessionId = "sess1";
Message<?> inputMessage = createInputMessage(sessionId, "sub1", null, null, null);
this.handler.handleReturnValue(PAYLOAD, this.userDefaultOverrideAnnotation, inputMessage);
verify(this.messageChannel, times(2)).send(this.messageCaptor.capture());
assertResponse(this.userDefaultOverrideAnnotation, sessionId, 0, "/user/sess1/dest3");
assertResponse(this.userDefaultOverrideAnnotation, sessionId, 1, "/user/sess1/dest4");
}
private void assertResponse(MethodParameter methodParameter, String sessionId,
int index, String destination) {
SimpMessageHeaderAccessor accessor = getCapturedAccessor(index);
@ -537,8 +591,8 @@ public class SendToMethodReturnValueHandlerTests { @@ -537,8 +591,8 @@ public class SendToMethodReturnValueHandlerTests {
return payload;
}
@SendTo("/dest-default")
private static class TestBean {
@SendTo("/dest-default") @SuppressWarnings("unused")
private static class SendToTestBean {
public String handleNoAnnotation() {
return PAYLOAD;
@ -556,6 +610,25 @@ public class SendToMethodReturnValueHandlerTests { @@ -556,6 +610,25 @@ public class SendToMethodReturnValueHandlerTests {
}
@SendToUser("/dest-default") @SuppressWarnings("unused")
private static class SendToUserTestBean {
public String handleNoAnnotation() {
return PAYLOAD;
}
@SendToUser
public String handleAndSendToDefaultDestination() {
return PAYLOAD;
}
@SendToUser({"/dest3", "/dest4"})
public String handleAndSendToOverride() {
return PAYLOAD;
}
}
private interface MyJacksonView1 {}
private interface MyJacksonView2 {}

3
src/asciidoc/web-websocket.adoc

@ -1700,7 +1700,8 @@ than their name and the generic destination. This is also supported through an @@ -1700,7 +1700,8 @@ than their name and the generic destination. This is also supported through an
annotation as well as a messaging template.
For example, a message-handling method can send messages to the user associated with
the message being handled through the `@SendToUser` annotation:
the message being handled through the `@SendToUser` annotation (also supported on
the class-level to share a common destination):
[source,java,indent=0]
[subs="verbatim,quotes"]

2
src/asciidoc/whats-new.adoc

@ -671,7 +671,7 @@ Spring 4.3 also improves the caching abstraction as follows: @@ -671,7 +671,7 @@ Spring 4.3 also improves the caching abstraction as follows:
=== WebSocket Messaging Improvements
* `@SendTo` can now be specified at class-level to share a common destination.
* `@SendTo` and `@SendToUser` can now be specified at class-level to share a common destination.
=== Testing Improvements

Loading…
Cancel
Save