Rename @SubscribeEvent to @SubscribeMapping
Also @SubscribeMapping is now a method-level annotation only that can be used in combination with a type-level @MessageMapping. This method also documents supported method arguments and return value types on @Subscribe- and @MessageMapping methods.
This commit is contained in:
@@ -26,8 +26,54 @@ import org.springframework.messaging.Message;
|
||||
|
||||
|
||||
/**
|
||||
* Annotation for mapping a {@link Message} onto message handling methods by matching to
|
||||
* the message destination.
|
||||
* Annotation for mapping a {@link Message} onto message-handling methods by matching
|
||||
* to the message destination. This annotation can also be used on the type-level in
|
||||
* which case it defines a common destination prefix or pattern for all method-level
|
||||
* annotations including method-level
|
||||
* {@link org.springframework.messaging.simp.annotation.SubscribeMapping @SubscribeMapping}
|
||||
* annotations.
|
||||
* <p>
|
||||
* Handler methods which are annotated with this annotation are allowed to have
|
||||
* flexible signatures. They may have arguments of the following types, in arbitrary
|
||||
* order:
|
||||
* <ul>
|
||||
* <li>{@link Message} to get access to the complete message being processed.</li>
|
||||
* <li>{@link Payload}-annotated method arguments to extract the payload of
|
||||
* a message and optionally convert it using a
|
||||
* {@link org.springframework.messaging.support.converter.MessageConverter}.
|
||||
* The presence of the annotation is not required since it is assumed by default
|
||||
* for method arguments that are not annotated.</li>
|
||||
* <li>{@link Header}-annotated method arguments to extract a specific
|
||||
* header value along with type conversion with a
|
||||
* {@link org.springframework.core.convert.converter.Converter} if necessary.</li>
|
||||
* <li>{@link Headers}-annotated argument that must also be assignable to
|
||||
* {@link java.util.Map} for getting access to all headers.</li>
|
||||
* <li>{@link org.springframework.messaging.MessageHeaders} arguments for
|
||||
* getting access to all headers.</li>
|
||||
* <li>{@link org.springframework.messaging.support.MessageHeaderAccessor} or
|
||||
* with STOMP over WebSocket support also sub-classes such as
|
||||
* {@link org.springframework.messaging.simp.SimpMessageHeaderAccessor}
|
||||
* for convenient access to all method arguments.</li>
|
||||
* <li>{@link PathVariable}-annotated arguments for access to URI variable
|
||||
* values extracted from the message destination (i.e. /hotels/{hotel}).
|
||||
* Variable values will be converted to the declared method argument type.</li>
|
||||
* <li>{@link java.security.Principal} method arguments are supported with
|
||||
* STOMP over WebSocket messages. It reflects the user logged in to the
|
||||
* WebSocket session on which the message was received. Regular HTTP-based
|
||||
* authentication (e.g. Spring Security based) can be used to secure the
|
||||
* HTTP handshake that initiates WebSocket sessions.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* By default the return value is wrapped as a message and sent to the destination
|
||||
* specified with an {@link SendTo} method-level annotation.
|
||||
* <p>
|
||||
* STOMP over WebSocket: an {@link SendTo} annotation is not strictly required --
|
||||
* by default the message will be sent to the same destination as the incoming
|
||||
* message but with an additional prefix ("/topic" by default). It is also possible
|
||||
* to use {@link org.springframework.messaging.simp.annotation.SendToUser} to
|
||||
* have the message directed to a specific user only if connected.
|
||||
* Also the return value is converted with a
|
||||
* {@link org.springframework.messaging.support.converter.MessageConverter}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.0
|
||||
|
||||
@@ -24,16 +24,31 @@ import java.lang.annotation.Target;
|
||||
|
||||
|
||||
/**
|
||||
* Annotation for mapping subscription events onto specific handler methods based
|
||||
* on the destination for the message (e.g. STOMP SUBSCRIBE message).
|
||||
* Annotation for mapping subscription messages onto specific handler methods based
|
||||
* on the destination of a subscription. Supported with STOMP over WebSocket only
|
||||
* (e.g. STOMP SUBSCRIBE frame).
|
||||
* <p>
|
||||
* This is a method-level annotations that can be combined with a type-level
|
||||
* {@link org.springframework.messaging.handler.annotation.MessageMapping @MessageMapping}
|
||||
* <p>
|
||||
* Supports the same method arguments as
|
||||
* {@link org.springframework.messaging.handler.annotation.MessageMapping}, however
|
||||
* subscription messages typically do not have a body.
|
||||
* <p>
|
||||
* The return value also follows the same rules as for
|
||||
* {@link org.springframework.messaging.handler.annotation.MessageMapping} except if
|
||||
* the method is not annotated with
|
||||
* {@link org.springframework.messaging.handler.annotation.SendTo} or {@link SendToUser},
|
||||
* the message is sent directly back to the connected user and does not pass through
|
||||
* the message broker. This is useful for implementing a request-reply pattern.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.0
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface SubscribeEvent {
|
||||
public @interface SubscribeMapping {
|
||||
|
||||
/**
|
||||
* Destination-based mapping expressed by this annotation.
|
||||
@@ -25,14 +25,14 @@ import org.springframework.messaging.handler.method.HandlerMethodReturnValueHand
|
||||
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||
import org.springframework.messaging.simp.SimpMessageType;
|
||||
import org.springframework.messaging.simp.annotation.SendToUser;
|
||||
import org.springframework.messaging.simp.annotation.SubscribeEvent;
|
||||
import org.springframework.messaging.simp.annotation.SubscribeMapping;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link HandlerMethodReturnValueHandler} for replying directly to a subscription. It
|
||||
* supports methods annotated with {@link SubscribeEvent} unless they're also annotated
|
||||
* supports methods annotated with {@link org.springframework.messaging.simp.annotation.SubscribeMapping} unless they're also annotated
|
||||
* with {@link SendTo} or {@link SendToUser}.
|
||||
* <p>
|
||||
* The value returned from the method is converted, and turned to a {@link Message} and
|
||||
@@ -55,7 +55,7 @@ public class SubscriptionMethodReturnValueHandler implements HandlerMethodReturn
|
||||
|
||||
@Override
|
||||
public boolean supportsReturnType(MethodParameter returnType) {
|
||||
return ((returnType.getMethodAnnotation(SubscribeEvent.class) != null)
|
||||
return ((returnType.getMethodAnnotation(SubscribeMapping.class) != null)
|
||||
&& (returnType.getMethodAnnotation(SendTo.class) == null)
|
||||
&& (returnType.getMethodAnnotation(SendToUser.class) == null));
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ import org.springframework.messaging.handler.method.HandlerMethodReturnValueHand
|
||||
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
|
||||
import org.springframework.messaging.simp.SimpMessageSendingOperations;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.messaging.simp.annotation.SubscribeEvent;
|
||||
import org.springframework.messaging.simp.annotation.SubscribeMapping;
|
||||
import org.springframework.messaging.simp.annotation.support.PrincipalMethodArgumentResolver;
|
||||
import org.springframework.messaging.simp.annotation.support.SendToMethodReturnValueHandler;
|
||||
import org.springframework.messaging.simp.annotation.support.SubscriptionMethodReturnValueHandler;
|
||||
@@ -66,7 +66,7 @@ import org.springframework.util.PathMatcher;
|
||||
|
||||
|
||||
/**
|
||||
* A handler for messages delegating to {@link SubscribeEvent @SubscribeEvent} and
|
||||
* A handler for messages delegating to {@link org.springframework.messaging.simp.annotation.SubscribeMapping @SubscribeMapping} and
|
||||
* {@link MessageMapping @MessageMapping} annotated methods.
|
||||
* <p>
|
||||
* Supports Ant-style path patterns as well as URI template variables in destinations.
|
||||
@@ -214,22 +214,21 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
@Override
|
||||
protected SimpMessageMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
||||
|
||||
MessageMapping messageMappingAnnot = AnnotationUtils.findAnnotation(method, MessageMapping.class);
|
||||
if (messageMappingAnnot != null) {
|
||||
SimpMessageMappingInfo result = createMessageMappingCondition(messageMappingAnnot);
|
||||
MessageMapping typeAnnot = AnnotationUtils.findAnnotation(handlerType, MessageMapping.class);
|
||||
MessageMapping typeAnnot = AnnotationUtils.findAnnotation(handlerType, MessageMapping.class);
|
||||
MessageMapping messageAnnot = AnnotationUtils.findAnnotation(method, MessageMapping.class);
|
||||
if (messageAnnot != null) {
|
||||
SimpMessageMappingInfo result = createMessageMappingCondition(messageAnnot);
|
||||
if (typeAnnot != null) {
|
||||
result = createMessageMappingCondition(typeAnnot).combine(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
SubscribeEvent subsribeAnnot = AnnotationUtils.findAnnotation(method, SubscribeEvent.class);
|
||||
SubscribeMapping subsribeAnnot = AnnotationUtils.findAnnotation(method, SubscribeMapping.class);
|
||||
if (subsribeAnnot != null) {
|
||||
SimpMessageMappingInfo result = createSubscribeCondition(subsribeAnnot);
|
||||
SubscribeEvent typeAnnot = AnnotationUtils.findAnnotation(handlerType, SubscribeEvent.class);
|
||||
if (typeAnnot != null) {
|
||||
result = createSubscribeCondition(typeAnnot).combine(result);
|
||||
result = createMessageMappingCondition(typeAnnot).combine(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -242,7 +241,7 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
|
||||
new DestinationPatternsMessageCondition(annotation.value()));
|
||||
}
|
||||
|
||||
private SimpMessageMappingInfo createSubscribeCondition(SubscribeEvent annotation) {
|
||||
private SimpMessageMappingInfo createSubscribeCondition(SubscribeMapping annotation) {
|
||||
return new SimpMessageMappingInfo(SimpMessageTypeMessageCondition.SUBSCRIBE,
|
||||
new DestinationPatternsMessageCondition(annotation.value()));
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* A message condition that checks the message type.
|
||||
@@ -44,13 +43,6 @@ public class SimpMessageTypeMessageCondition extends AbstractMessageCondition<Si
|
||||
private final SimpMessageType messageType;
|
||||
|
||||
|
||||
/**
|
||||
* A constructor accepting a message type.
|
||||
*/
|
||||
public SimpMessageTypeMessageCondition() {
|
||||
this.messageType = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A constructor accepting a message type.
|
||||
*
|
||||
@@ -68,7 +60,7 @@ public class SimpMessageTypeMessageCondition extends AbstractMessageCondition<Si
|
||||
|
||||
@Override
|
||||
protected Collection<?> getContent() {
|
||||
return (this.messageType != null) ? Arrays.asList(messageType) : Collections.emptyList();
|
||||
return Arrays.asList(messageType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,7 +70,7 @@ public class SimpMessageTypeMessageCondition extends AbstractMessageCondition<Si
|
||||
|
||||
@Override
|
||||
public SimpMessageTypeMessageCondition combine(SimpMessageTypeMessageCondition other) {
|
||||
return (this.messageType != null) ? this : other;
|
||||
return other;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -89,19 +81,22 @@ public class SimpMessageTypeMessageCondition extends AbstractMessageCondition<Si
|
||||
return null;
|
||||
}
|
||||
|
||||
return ((this.messageType != null) && this.messageType.equals(actualMessageType)) ? this : null;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(SimpMessageTypeMessageCondition other, Message<?> message) {
|
||||
if ((this.messageType == null) && (other.messageType == null)) {
|
||||
return 0;
|
||||
}
|
||||
if (this.messageType == null) {
|
||||
return 1;
|
||||
}
|
||||
if (other.messageType == null) {
|
||||
return -1;
|
||||
Object actualMessageType = message.getHeaders().get(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER);
|
||||
if (actualMessageType != null) {
|
||||
if (actualMessageType.equals(this.getMessageType()) && actualMessageType.equals(other.getMessageType())) {
|
||||
return 0;
|
||||
}
|
||||
else if (actualMessageType.equals(this.getMessageType())) {
|
||||
return -1;
|
||||
}
|
||||
else if (actualMessageType.equals(other.getMessageType())) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user