Skip to content

Commit d196cdc

Browse files
committed
Update docs on @sendto and @SendToUser
1. Explain that both can be used on the same method 2. Better describe semantics for class vs method level 3. General improvements Issue: SPR-16336
1 parent f4bffea commit d196cdc

File tree

4 files changed

+61
-58
lines changed

4 files changed

+61
-58
lines changed

spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/SendTo.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,8 @@
3232
* convey the destination to use for the reply. In that case, that destination
3333
* should take precedence.
3434
*
35-
* <p>The annotation may also be placed at class-level if the provider supports
36-
* it to indicate that all related methods should use this destination if none
37-
* is specified otherwise.
35+
* <p>This annotation may be placed class-level in which case it is inherited by
36+
* methods of the class.
3837
*
3938
* @author Rossen Stoyanchev
4039
* @author Stephane Nicoll

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

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,13 +25,17 @@
2525
import org.springframework.core.annotation.AliasFor;
2626

2727
/**
28-
* Annotation that indicates that the return value of a message-handling method
29-
* should be sent as a {@link org.springframework.messaging.Message} to the specified
30-
* destination(s) prepended with <code>"/user/{username}"</code> where the user name
28+
* Indicates the return value of a message-handling method should be sent as a
29+
* {@link org.springframework.messaging.Message} to the specified destination(s)
30+
* further prepended with <code>"/user/{username}"</code> where the user name
3131
* is extracted from the headers of the input message being handled.
3232
*
33-
* <p>The annotation may also be placed at class-level in which case all methods
34-
* in the class where the annotation applies will inherit it.
33+
* <p>Both {@code @SendTo} and {@code @SendToUser} may be used on the same method
34+
* in which case a message is sent to the destinations of both annotations.
35+
*
36+
* <p>This annotation may be placed class-level in which case it is inherited
37+
* by methods of the class. At the same time, method-level {@code @SendTo} or
38+
* {@code @SendToUser} annotations override any such at the class level.
3539
3640
* @author Rossen Stoyanchev
3741
* @author Sam Brannen

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -330,15 +330,14 @@ protected List<? extends HandlerMethodReturnValueHandler> initReturnValueHandler
330330
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
331331

332332
// Single-purpose return value types
333+
333334
handlers.add(new ListenableFutureReturnValueHandler());
334335
handlers.add(new CompletableFutureReturnValueHandler());
335336

336337
// Annotation-based return value types
337-
SendToMethodReturnValueHandler sendToHandler =
338-
new SendToMethodReturnValueHandler(this.brokerTemplate, true);
339-
if (this.headerInitializer != null) {
340-
sendToHandler.setHeaderInitializer(this.headerInitializer);
341-
}
338+
339+
SendToMethodReturnValueHandler sendToHandler = new SendToMethodReturnValueHandler(this.brokerTemplate, true);
340+
sendToHandler.setHeaderInitializer(this.headerInitializer);
342341
handlers.add(sendToHandler);
343342

344343
SubscriptionMethodReturnValueHandler subscriptionHandler =
@@ -350,6 +349,7 @@ protected List<? extends HandlerMethodReturnValueHandler> initReturnValueHandler
350349
handlers.addAll(getCustomReturnValueHandlers());
351350

352351
// catch-all
352+
353353
sendToHandler = new SendToMethodReturnValueHandler(this.brokerTemplate, false);
354354
sendToHandler.setHeaderInitializer(this.headerInitializer);
355355
handlers.add(sendToHandler);

src/docs/asciidoc/web/websocket.adoc

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,22 +1214,17 @@ methods as described next.
12141214
[[websocket-stomp-message-mapping]]
12151215
==== `@MessageMapping`
12161216

1217-
The `@MessageMapping` annotation can be used on methods to route messages based on their
1217+
`@MessageMapping` can be used to annotate methods to route messages based on their
12181218
destination. It is supported at the method level as well as at the type level. At type
12191219
level `@MessageMapping` is used to express shared mappings across all methods in a
12201220
controller.
12211221

1222-
By default destination mappings are expected to be Ant-style, path patterns, e.g. "/foo*",
1223-
"/foo/**". The patterns include support for template variables, e.g. "/foo/{id}", that can
1224-
be referenced with `@DestinationVariable` method arguments.
1222+
The mapping values are Ant-style path patterns by default, e.g. "/foo*", "/foo/**"
1223+
including support for template variables, e.g. "/foo/{id}", that can be referenced via
1224+
`@DestinationVariable` method arguments. Applications can also switch to a dot-separated
1225+
destination convention for mappings, as explained in <<websocket-stomp-destination-separator>>.
12251226

1226-
[TIP]
1227-
====
1228-
Applications can choose to switch to a dot-separated destination convention.
1229-
See <<websocket-stomp-destination-separator>>.
1230-
====
1231-
1232-
`@MessageMapping` methods can have flexible signatures with the following arguments:
1227+
*Supported Method Arguments*
12331228

12341229
[cols="1,2", options="header"]
12351230
|===
@@ -1271,47 +1266,52 @@ Values will be converted to the declared method argument type as necessary.
12711266

12721267
|===
12731268

1274-
When an `@MessageMapping` method returns a value, by default the value is serialized to
1275-
a payload through a configured `MessageConverter`, and then sent as a `Message` to the
1276-
`"brokerChannel"` from where it is broadcast to subscribers. The destination of the
1277-
outbound message is the same as that of the inbound message but prefixed with `"/topic"`.
1269+
*Return Values*
1270+
1271+
By default, the return value from an `@MessageMapping` method is serialized to a payload
1272+
through a matching `MessageConverter`, and sent as a `Message` to the `"brokerChannel"`
1273+
from where it is broadcast to subscribers. The destination of the outbound message is the
1274+
same as that of the inbound message but prefixed with `"/topic"`.
1275+
1276+
The `@SendTo` and `@SendToUser` annotations can be used to customize the destination of
1277+
the output message. `@SendTo` is used to simply customize target destination, or to
1278+
specify multiple destinations. `@SendToUser` is used to direct the output message only
1279+
to the user associated with the input message, see <<websocket-stomp-user-destination>>.
12781280

1279-
You can use the `@SendTo` method annotation to customize the destination to send
1280-
the payload to. `@SendTo` can also be used at the class level to share a default target
1281-
destination to send messages to. `@SendToUser` is an variant for sending messages only to
1282-
the user associated with a message. See <<websocket-stomp-user-destination>> for details.
1281+
`@SendTo` and `@SendToUser` may both be used at the same time on the same method, and both
1282+
are supported at the class level in which case they act as a default for methods in the
1283+
class. However keep in mind that _any_ method-level `@SendTo` or `@SendToUser` annotations
1284+
override _any_ such annotations at the class level.
12831285

1284-
The return value from an `@MessageMapping` method may be wrapped with `ListenableFuture`,
1285-
`CompletableFuture`, or `CompletionStage` in order to produce the payload asynchronously.
1286+
Messages may be handled asynchronously and a `@MessageMapping` method may return
1287+
`ListenableFuture`, `CompletableFuture`, or `CompletionStage`.
12861288

1287-
As an alternative to returning a payload from an `@MessageMapping` method you can also
1288-
send messages using the `SimpMessagingTemplate`, which is also how return values are
1289-
handled under the covers. See <<websocket-stomp-handle-send>>.
1289+
Note that `@SendTo` and `@SendToUser` are merely a convenience that amounts to using the
1290+
`SimpMessagingTemplate` to send messages. If necessary, for more advanced scenarios,
1291+
`@MessageMapping` methods can fall back on using the `SimpMessagingTemplate` directly.
1292+
This can be done instead of, or possibly in addition to returning a value.
1293+
See <<websocket-stomp-handle-send>>.
12901294

12911295

12921296
[[websocket-stomp-subscribe-mapping]]
12931297
==== `@SubscribeMapping`
12941298

1295-
The `@SubscribeMapping` annotation is used in combination with `@MessageMapping` in order
1296-
to narrow the mapping to subscription messages. In such scenarios, the `@MessageMapping`
1297-
annotation specifies the destination while `@SubscribeMapping` indicates interest in
1298-
subscription messages only.
1299-
1300-
An `@SubscribeMapping` method is generally no different from any `@MessageMapping`
1301-
method with respect to mapping and input arguments. For example you can combine it with a
1302-
type-level `@MessageMapping` to express a shared destination prefix, and you can use the
1303-
same <<websocket-stomp-message-mapping,method arguments>> as any @MessageMapping` method.
1304-
1305-
The key difference with `@SubscribeMapping` is that the return value of the method is
1306-
serialized as a payload and sent, not to the "brokerChannel" but to the
1307-
"clientOutboundChannel", effectively replying directly to the client rather than
1308-
broadcasting through the broker. This is useful for implementing one-off, request-reply
1309-
message exchanges, and never holding on to the subscription. A common scenario for this
1310-
pattern is application initialization when data must be loaded and presented.
1311-
1312-
A `@SubscribeMapping` method can also be annotated with `@SendTo` in which case the
1313-
return value is sent to the `"brokerChannel"` with the explicitly specified target
1314-
destination.
1299+
`@SubscribeMapping` is used together with `@MessageMapping` to narrow the mapping to
1300+
subscription messages. In this scenario `@MessageMapping` expresses message destination
1301+
mappings for routing purposes, which can be done at the class or at the method level,
1302+
while `@SubscribeMapping` narrows the mapping to subscription messages only.
1303+
1304+
Methods with `@MessageMapping` and `@SubscribeMapping` support the same
1305+
<<websocket-stomp-message-mapping,method arguments>> as methods annotated only with
1306+
`@MessageMapping` do. However for the return value, in the absence of `@SendTo` and
1307+
`@SendToUser`, a message is sent directly as a reply to the subscription, via the
1308+
"clientOutboundChannel" channel. Effectively the subscription is used as a one-time,
1309+
request-reply message exchange with the subscription never stored. This is useful for
1310+
loading data on startup and for initializing a front-end UI.
1311+
1312+
If an `@SubscribeMapping` method is annotated with `@SendTo` and `@SendToUser` the return
1313+
value is sent to the `"brokerChannel"` as usual, sending a message subscribers of the
1314+
specified destination(s).
13151315

13161316

13171317
[[websocket-stomp-exception-handler]]

0 commit comments

Comments
 (0)