diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/SendTo.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/SendTo.java
index 0a5a3f27531..83b3af200b5 100644
--- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/SendTo.java
+++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/SendTo.java
@@ -32,9 +32,8 @@ import org.springframework.messaging.Message;
* convey the destination to use for the reply. In that case, that destination
* should take precedence.
*
- *
The annotation may also be placed at class-level if the provider supports
- * it to indicate that all related methods should use this destination if none
- * is specified otherwise.
+*
This annotation may be placed class-level in which case it is inherited by
+ * methods of the class.
*
* @author Rossen Stoyanchev
* @author Stephane Nicoll
diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/SendToUser.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/SendToUser.java
index 255e1238eae..33f5fac6d6f 100644
--- a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/SendToUser.java
+++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/SendToUser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2016 the original author or authors.
+ * Copyright 2002-2018 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.
@@ -25,13 +25,17 @@ import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
/**
- * Annotation that indicates that the return value of a message-handling method
- * should be sent as a {@link org.springframework.messaging.Message} to the specified
- * destination(s) prepended with "/user/{username}" where the user name
+ * Indicates the return value of a message-handling method should be sent as a
+ * {@link org.springframework.messaging.Message} to the specified destination(s)
+ * further prepended with "/user/{username}" where the user name
* is extracted from the headers of the input message being handled.
*
- *
The annotation may also be placed at class-level in which case all methods
- * in the class where the annotation applies will inherit it.
+ *
Both {@code @SendTo} and {@code @SendToUser} may be used on the same method
+ * in which case a message is sent to the destinations of both annotations.
+ *
+ *
This annotation may be placed class-level in which case it is inherited
+ * by methods of the class. At the same time, method-level {@code @SendTo} or
+ * {@code @SendToUser} annotations override any such at the class level.
* @author Rossen Stoyanchev
* @author Sam Brannen
diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java
index 7ee2bdcf963..90b4a3d91e6 100644
--- a/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java
+++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java
@@ -330,15 +330,14 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
List handlers = new ArrayList<>();
// Single-purpose return value types
+
handlers.add(new ListenableFutureReturnValueHandler());
handlers.add(new CompletableFutureReturnValueHandler());
// Annotation-based return value types
- SendToMethodReturnValueHandler sendToHandler =
- new SendToMethodReturnValueHandler(this.brokerTemplate, true);
- if (this.headerInitializer != null) {
- sendToHandler.setHeaderInitializer(this.headerInitializer);
- }
+
+ SendToMethodReturnValueHandler sendToHandler = new SendToMethodReturnValueHandler(this.brokerTemplate, true);
+ sendToHandler.setHeaderInitializer(this.headerInitializer);
handlers.add(sendToHandler);
SubscriptionMethodReturnValueHandler subscriptionHandler =
@@ -350,6 +349,7 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
handlers.addAll(getCustomReturnValueHandlers());
// catch-all
+
sendToHandler = new SendToMethodReturnValueHandler(this.brokerTemplate, false);
sendToHandler.setHeaderInitializer(this.headerInitializer);
handlers.add(sendToHandler);
diff --git a/src/docs/asciidoc/web/websocket.adoc b/src/docs/asciidoc/web/websocket.adoc
index b7627d82ba2..3c36722719e 100644
--- a/src/docs/asciidoc/web/websocket.adoc
+++ b/src/docs/asciidoc/web/websocket.adoc
@@ -1214,22 +1214,17 @@ methods as described next.
[[websocket-stomp-message-mapping]]
==== `@MessageMapping`
-The `@MessageMapping` annotation can be used on methods to route messages based on their
+`@MessageMapping` can be used to annotate methods to route messages based on their
destination. It is supported at the method level as well as at the type level. At type
level `@MessageMapping` is used to express shared mappings across all methods in a
controller.
-By default destination mappings are expected to be Ant-style, path patterns, e.g. "/foo*",
-"/foo/**". The patterns include support for template variables, e.g. "/foo/{id}", that can
-be referenced with `@DestinationVariable` method arguments.
+The mapping values are Ant-style path patterns by default, e.g. "/foo*", "/foo/**"
+including support for template variables, e.g. "/foo/{id}", that can be referenced via
+`@DestinationVariable` method arguments. Applications can also switch to a dot-separated
+destination convention for mappings, as explained in <>.
-[TIP]
-====
-Applications can choose to switch to a dot-separated destination convention.
-See <>.
-====
-
-`@MessageMapping` methods can have flexible signatures with the following arguments:
+*Supported Method Arguments*
[cols="1,2", options="header"]
|===
@@ -1271,47 +1266,52 @@ Values will be converted to the declared method argument type as necessary.
|===
-When an `@MessageMapping` method returns a value, by default the value is serialized to
-a payload through a configured `MessageConverter`, and then sent as a `Message` to the
-`"brokerChannel"` from where it is broadcast to subscribers. The destination of the
-outbound message is the same as that of the inbound message but prefixed with `"/topic"`.
+*Return Values*
-You can use the `@SendTo` method annotation to customize the destination to send
-the payload to. `@SendTo` can also be used at the class level to share a default target
-destination to send messages to. `@SendToUser` is an variant for sending messages only to
-the user associated with a message. See <> for details.
+By default, the return value from an `@MessageMapping` method is serialized to a payload
+through a matching `MessageConverter`, and sent as a `Message` to the `"brokerChannel"`
+from where it is broadcast to subscribers. The destination of the outbound message is the
+same as that of the inbound message but prefixed with `"/topic"`.
-The return value from an `@MessageMapping` method may be wrapped with `ListenableFuture`,
-`CompletableFuture`, or `CompletionStage` in order to produce the payload asynchronously.
+The `@SendTo` and `@SendToUser` annotations can be used to customize the destination of
+the output message. `@SendTo` is used to simply customize target destination, or to
+specify multiple destinations. `@SendToUser` is used to direct the output message only
+to the user associated with the input message, see <>.
-As an alternative to returning a payload from an `@MessageMapping` method you can also
-send messages using the `SimpMessagingTemplate`, which is also how return values are
-handled under the covers. See <>.
+`@SendTo` and `@SendToUser` may both be used at the same time on the same method, and both
+are supported at the class level in which case they act as a default for methods in the
+class. However keep in mind that _any_ method-level `@SendTo` or `@SendToUser` annotations
+override _any_ such annotations at the class level.
+
+Messages may be handled asynchronously and a `@MessageMapping` method may return
+`ListenableFuture`, `CompletableFuture`, or `CompletionStage`.
+
+Note that `@SendTo` and `@SendToUser` are merely a convenience that amounts to using the
+`SimpMessagingTemplate` to send messages. If necessary, for more advanced scenarios,
+`@MessageMapping` methods can fall back on using the `SimpMessagingTemplate` directly.
+This can be done instead of, or possibly in addition to returning a value.
+See <>.
[[websocket-stomp-subscribe-mapping]]
==== `@SubscribeMapping`
-The `@SubscribeMapping` annotation is used in combination with `@MessageMapping` in order
-to narrow the mapping to subscription messages. In such scenarios, the `@MessageMapping`
-annotation specifies the destination while `@SubscribeMapping` indicates interest in
-subscription messages only.
+`@SubscribeMapping` is used together with `@MessageMapping` to narrow the mapping to
+subscription messages. In this scenario `@MessageMapping` expresses message destination
+mappings for routing purposes, which can be done at the class or at the method level,
+while `@SubscribeMapping` narrows the mapping to subscription messages only.
-An `@SubscribeMapping` method is generally no different from any `@MessageMapping`
-method with respect to mapping and input arguments. For example you can combine it with a
-type-level `@MessageMapping` to express a shared destination prefix, and you can use the
-same <> as any @MessageMapping` method.
+Methods with `@MessageMapping` and `@SubscribeMapping` support the same
+<> as methods annotated only with
+`@MessageMapping` do. However for the return value, in the absence of `@SendTo` and
+`@SendToUser`, a message is sent directly as a reply to the subscription, via the
+"clientOutboundChannel" channel. Effectively the subscription is used as a one-time,
+request-reply message exchange with the subscription never stored. This is useful for
+loading data on startup and for initializing a front-end UI.
-The key difference with `@SubscribeMapping` is that the return value of the method is
-serialized as a payload and sent, not to the "brokerChannel" but to the
-"clientOutboundChannel", effectively replying directly to the client rather than
-broadcasting through the broker. This is useful for implementing one-off, request-reply
-message exchanges, and never holding on to the subscription. A common scenario for this
-pattern is application initialization when data must be loaded and presented.
-
-A `@SubscribeMapping` method can also be annotated with `@SendTo` in which case the
-return value is sent to the `"brokerChannel"` with the explicitly specified target
-destination.
+If an `@SubscribeMapping` method is annotated with `@SendTo` and `@SendToUser` the return
+value is sent to the `"brokerChannel"` as usual, sending a message subscribers of the
+specified destination(s).
[[websocket-stomp-exception-handler]]