提交 03e3ef53 编写于 作者: R Rossen Stoyanchev

@SendToUser supported on the class level

Issue: SPR-12047
上级 bedf1a9b
/*
* 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;
* 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;
* @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 {
......
......@@ -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
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
}
}
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()))) {
......
......@@ -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 {
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 {
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 {
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 {
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 {
}
@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 {}
......
......@@ -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"]
......
......@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册