Support for @SendTo and @SendToUser for same method
Issue: SPR-16891
This commit is contained in:
parent
7a70f7c5d8
commit
f4bffea739
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2017 the original author or authors.
|
* Copyright 2002-2018 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -18,6 +18,7 @@ package org.springframework.messaging.simp.annotation.support;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
|
@ -153,11 +154,10 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
|
||||||
|
|
||||||
MessageHeaders headers = message.getHeaders();
|
MessageHeaders headers = message.getHeaders();
|
||||||
String sessionId = SimpMessageHeaderAccessor.getSessionId(headers);
|
String sessionId = SimpMessageHeaderAccessor.getSessionId(headers);
|
||||||
PlaceholderResolver varResolver = initVarResolver(headers);
|
DestinationHelper destinationHelper = getDestinationHelper(headers, returnType);
|
||||||
Object annotation = findAnnotation(returnType);
|
|
||||||
|
|
||||||
if (annotation instanceof SendToUser) {
|
SendToUser sendToUser = destinationHelper.getSendToUser();
|
||||||
SendToUser sendToUser = (SendToUser) annotation;
|
if (sendToUser != null) {
|
||||||
boolean broadcast = sendToUser.broadcast();
|
boolean broadcast = sendToUser.broadcast();
|
||||||
String user = getUserName(message, headers);
|
String user = getUserName(message, headers);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
|
@ -169,7 +169,7 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
|
||||||
}
|
}
|
||||||
String[] destinations = getTargetDestinations(sendToUser, message, this.defaultUserDestinationPrefix);
|
String[] destinations = getTargetDestinations(sendToUser, message, this.defaultUserDestinationPrefix);
|
||||||
for (String destination : destinations) {
|
for (String destination : destinations) {
|
||||||
destination = this.placeholderHelper.replacePlaceholders(destination, varResolver);
|
destination = destinationHelper.expandTemplateVars(destination);
|
||||||
if (broadcast) {
|
if (broadcast) {
|
||||||
this.messagingTemplate.convertAndSendToUser(
|
this.messagingTemplate.convertAndSendToUser(
|
||||||
user, destination, returnValue, createHeaders(null, returnType));
|
user, destination, returnValue, createHeaders(null, returnType));
|
||||||
|
@ -180,51 +180,33 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
SendTo sendTo = (SendTo) annotation; // possibly null
|
SendTo sendTo = destinationHelper.getSendTo();
|
||||||
|
if (sendTo != null || sendToUser == null) {
|
||||||
String[] destinations = getTargetDestinations(sendTo, message, this.defaultDestinationPrefix);
|
String[] destinations = getTargetDestinations(sendTo, message, this.defaultDestinationPrefix);
|
||||||
for (String destination : destinations) {
|
for (String destination : destinations) {
|
||||||
destination = this.placeholderHelper.replacePlaceholders(destination, varResolver);
|
destination = destinationHelper.expandTemplateVars(destination);
|
||||||
this.messagingTemplate.convertAndSend(destination, returnValue, createHeaders(sessionId, returnType));
|
this.messagingTemplate.convertAndSend(destination, returnValue, createHeaders(sessionId, returnType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
private DestinationHelper getDestinationHelper(MessageHeaders headers, MethodParameter returnType) {
|
||||||
private Object findAnnotation(MethodParameter returnType) {
|
|
||||||
Annotation[] anns = new Annotation[4];
|
|
||||||
anns[0] = AnnotatedElementUtils.findMergedAnnotation(returnType.getExecutable(), SendToUser.class);
|
|
||||||
anns[1] = AnnotatedElementUtils.findMergedAnnotation(returnType.getExecutable(), SendTo.class);
|
|
||||||
anns[2] = AnnotatedElementUtils.findMergedAnnotation(returnType.getDeclaringClass(), SendToUser.class);
|
|
||||||
anns[3] = AnnotatedElementUtils.findMergedAnnotation(returnType.getDeclaringClass(), SendTo.class);
|
|
||||||
|
|
||||||
if (anns[0] != null && !ObjectUtils.isEmpty(((SendToUser) anns[0]).value())) {
|
SendToUser m1 = AnnotatedElementUtils.findMergedAnnotation(returnType.getExecutable(), SendToUser.class);
|
||||||
return anns[0];
|
SendTo m2 = AnnotatedElementUtils.findMergedAnnotation(returnType.getExecutable(), SendTo.class);
|
||||||
}
|
if ((m1 != null && !ObjectUtils.isEmpty(m1.value())) || (m2 != null && !ObjectUtils.isEmpty(m2.value()))) {
|
||||||
if (anns[1] != null && !ObjectUtils.isEmpty(((SendTo) anns[1]).value())) {
|
return new DestinationHelper(headers, m1, m2);
|
||||||
return anns[1];
|
|
||||||
}
|
|
||||||
if (anns[2] != null && !ObjectUtils.isEmpty(((SendToUser) anns[2]).value())) {
|
|
||||||
return anns[2];
|
|
||||||
}
|
|
||||||
if (anns[3] != null && !ObjectUtils.isEmpty(((SendTo) anns[3]).value())) {
|
|
||||||
return anns[3];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i < 4; i++) {
|
SendToUser c1 = AnnotatedElementUtils.findMergedAnnotation(returnType.getDeclaringClass(), SendToUser.class);
|
||||||
if (anns[i] != null) {
|
SendTo c2 = AnnotatedElementUtils.findMergedAnnotation(returnType.getDeclaringClass(), SendTo.class);
|
||||||
return anns[i];
|
if ((c1 != null && !ObjectUtils.isEmpty(c1.value())) || (c2 != null && !ObjectUtils.isEmpty(c2.value()))) {
|
||||||
}
|
return new DestinationHelper(headers, c1, c2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return m1 != null || m2 != null ?
|
||||||
}
|
new DestinationHelper(headers, m1, m2) : new DestinationHelper(headers, c1, c2);
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private PlaceholderResolver initVarResolver(MessageHeaders headers) {
|
|
||||||
String name = DestinationVariableMethodArgumentResolver.DESTINATION_TEMPLATE_VARIABLES_HEADER;
|
|
||||||
Map<String, String> vars = (Map<String, String>) headers.get(name);
|
|
||||||
return new DestinationVariablePlaceholderResolver(vars);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -275,20 +257,43 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class DestinationVariablePlaceholderResolver implements PlaceholderResolver {
|
private class DestinationHelper {
|
||||||
|
|
||||||
|
private final PlaceholderResolver placeholderResolver;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private final Map<String, String> vars;
|
private final SendTo sendTo;
|
||||||
|
|
||||||
public DestinationVariablePlaceholderResolver(@Nullable Map<String, String> vars) {
|
@Nullable
|
||||||
this.vars = vars;
|
private final SendToUser sendToUser;
|
||||||
|
|
||||||
|
|
||||||
|
public DestinationHelper(MessageHeaders headers, @Nullable SendToUser sendToUser, @Nullable SendTo sendTo) {
|
||||||
|
Map<String, String> variables = getTemplateVariables(headers);
|
||||||
|
this.placeholderResolver = variables::get;
|
||||||
|
this.sendTo = sendTo;
|
||||||
|
this.sendToUser = sendToUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private Map<String, String> getTemplateVariables(MessageHeaders headers) {
|
||||||
|
String name = DestinationVariableMethodArgumentResolver.DESTINATION_TEMPLATE_VARIABLES_HEADER;
|
||||||
|
return (Map<String, String>) headers.getOrDefault(name, Collections.emptyMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public String resolvePlaceholder(String placeholderName) {
|
public SendTo getSendTo() {
|
||||||
return (this.vars != null ? this.vars.get(placeholderName) : null);
|
return this.sendTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public SendToUser getSendToUser() {
|
||||||
|
return this.sendToUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String expandTemplateVars(String destination) {
|
||||||
|
return placeholderHelper.replacePlaceholders(destination, this.placeholderResolver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
|
@ -87,6 +87,7 @@ public class SendToMethodReturnValueHandlerTests {
|
||||||
private MethodParameter sendToWithPlaceholdersReturnType = param("handleAndSendToWithPlaceholders");
|
private MethodParameter sendToWithPlaceholdersReturnType = param("handleAndSendToWithPlaceholders");
|
||||||
private MethodParameter sendToUserReturnType = param("handleAndSendToUser");
|
private MethodParameter sendToUserReturnType = param("handleAndSendToUser");
|
||||||
private MethodParameter sendToUserInSessionReturnType = param("handleAndSendToUserInSession");
|
private MethodParameter sendToUserInSessionReturnType = param("handleAndSendToUserInSession");
|
||||||
|
private MethodParameter sendToSendToUserReturnType = param("handleAndSendToAndSendToUser");
|
||||||
private MethodParameter sendToUserDefaultDestReturnType = param("handleAndSendToUserDefaultDest");
|
private MethodParameter sendToUserDefaultDestReturnType = param("handleAndSendToUserDefaultDest");
|
||||||
private MethodParameter sendToUserInSessionDefaultDestReturnType = param("handleAndSendToUserDefaultDestInSession");
|
private MethodParameter sendToUserInSessionDefaultDestReturnType = param("handleAndSendToUserDefaultDestInSession");
|
||||||
private MethodParameter jsonViewReturnType = param("handleAndSendToJsonView");
|
private MethodParameter jsonViewReturnType = param("handleAndSendToJsonView");
|
||||||
|
@ -355,6 +356,38 @@ public class SendToMethodReturnValueHandlerTests {
|
||||||
assertEquals("/user/" + user.getName() + "/dest2", accessor.getDestination());
|
assertEquals("/user/" + user.getName() + "/dest2", accessor.getDestination());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void sendToAndSendToUser() throws Exception {
|
||||||
|
given(this.messageChannel.send(any(Message.class))).willReturn(true);
|
||||||
|
|
||||||
|
String sessionId = "sess1";
|
||||||
|
TestUser user = new TestUser();
|
||||||
|
Message<?> inputMessage = createMessage(sessionId, "sub1", null, null, user);
|
||||||
|
this.handler.handleReturnValue(PAYLOAD, this.sendToSendToUserReturnType, inputMessage);
|
||||||
|
|
||||||
|
verify(this.messageChannel, times(4)).send(this.messageCaptor.capture());
|
||||||
|
|
||||||
|
SimpMessageHeaderAccessor accessor = getCapturedAccessor(0);
|
||||||
|
assertNull(accessor.getSessionId());
|
||||||
|
assertNull(accessor.getSubscriptionId());
|
||||||
|
assertEquals("/user/" + user.getName() + "/dest1", accessor.getDestination());
|
||||||
|
|
||||||
|
accessor = getCapturedAccessor(1);
|
||||||
|
assertNull(accessor.getSessionId());
|
||||||
|
assertNull(accessor.getSubscriptionId());
|
||||||
|
assertEquals("/user/" + user.getName() + "/dest2", accessor.getDestination());
|
||||||
|
|
||||||
|
accessor = getCapturedAccessor(2);
|
||||||
|
assertEquals("sess1", accessor.getSessionId());
|
||||||
|
assertNull(accessor.getSubscriptionId());
|
||||||
|
assertEquals("/dest1", accessor.getDestination());
|
||||||
|
|
||||||
|
accessor = getCapturedAccessor(3);
|
||||||
|
assertEquals("sess1", accessor.getSessionId());
|
||||||
|
assertNull(accessor.getSubscriptionId());
|
||||||
|
assertEquals("/dest2", accessor.getDestination());
|
||||||
|
}
|
||||||
|
|
||||||
@Test // SPR-12170
|
@Test // SPR-12170
|
||||||
public void sendToWithDestinationPlaceholders() throws Exception {
|
public void sendToWithDestinationPlaceholders() throws Exception {
|
||||||
given(this.messageChannel.send(any(Message.class))).willReturn(true);
|
given(this.messageChannel.send(any(Message.class))).willReturn(true);
|
||||||
|
@ -577,6 +610,13 @@ public class SendToMethodReturnValueHandlerTests {
|
||||||
return PAYLOAD;
|
return PAYLOAD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SendTo({"/dest1", "/dest2"})
|
||||||
|
@SendToUser({"/dest1", "/dest2"})
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
String handleAndSendToAndSendToUser() {
|
||||||
|
return PAYLOAD;
|
||||||
|
}
|
||||||
|
|
||||||
@JsonView(MyJacksonView1.class)
|
@JsonView(MyJacksonView1.class)
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
JacksonViewBean handleAndSendToJsonView() {
|
JacksonViewBean handleAndSendToJsonView() {
|
||||||
|
|
Loading…
Reference in New Issue