diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessageMapping.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessageMapping.java index aa2a635a7a..a14dac5e0f 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessageMapping.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/MessageMapping.java @@ -26,11 +26,13 @@ import org.springframework.messaging.Message; /** - * Annotation for mapping a {@link Message} onto specific handler methods based on - * the destination for the message. + * Annotation for mapping a {@link Message} onto message handling methods by matching to + * the message destination. * * @author Rossen Stoyanchev * @since 4.0 + * + * @see org.springframework.messaging.simp.handler.AnnotationMethodMessageHandler */ @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @@ -38,7 +40,11 @@ import org.springframework.messaging.Message; public @interface MessageMapping { /** - * Destination values for the message. + * Destination-based mapping expressed by this annotation. + *
+ * For STOMP over WebSocket messages: this is the destination of the STOMP message + * (e.g. "/positions"). Ant-style path patterns (e.g. "/price.stock.*") are supported + * and so are path template variables (e.g. "/price.stock.{ticker}""). */ String[] value() default {}; diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/PathVariable.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/PathVariable.java index 00b21e9a74..52eb2fbf3c 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/PathVariable.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/PathVariable.java @@ -23,19 +23,17 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Annotation which indicates that a method parameter should be bound to a path template - * variable. Supported for {@link org.springframework.messaging.simp.annotation.SubscribeEvent}, - * {@link org.springframework.messaging.simp.annotation.UnsubscribeEvent}, - * {@link org.springframework.messaging.handler.annotation.MessageMapping} - * annotated handler methods. - * - *
A {@code @PathVariable} template variable is always required and does not have - * a default value to fall back on. + * Annotation that indicates a method parameter should be bound to a path template + * variable. Supported on message handling methods such as {@link MessageMapping + * @MessageMapping} for messages with path-like destination semantics. + *
+ * A {@code @PathVariable} template variable is always required and does not have a
+ * default value to fall back on.
*
* @author Brian Clozel
- * @see org.springframework.messaging.simp.annotation.SubscribeEvent
- * @see org.springframework.messaging.simp.annotation.UnsubscribeEvent
* @see org.springframework.messaging.handler.annotation.MessageMapping
+ * @see org.springframework.messaging.simp.handler.AnnotationMethodMessageHandler
+ *
* @since 4.0
*/
@Target(ElementType.PARAMETER)
@@ -43,6 +41,9 @@ import java.lang.annotation.Target;
@Documented
public @interface PathVariable {
- /** The path template variable to bind to. */
+ /**
+ * The path template variable to bind to.
+ */
String value() default "";
+
}
diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PathVariableMethodArgumentResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PathVariableMethodArgumentResolver.java
index d095211913..d2eca95239 100644
--- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PathVariableMethodArgumentResolver.java
+++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PathVariableMethodArgumentResolver.java
@@ -16,7 +16,8 @@
package org.springframework.messaging.handler.annotation.support;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import java.util.Map;
+
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.ConversionService;
import org.springframework.messaging.Message;
@@ -24,8 +25,6 @@ import org.springframework.messaging.handler.annotation.PathVariable;
import org.springframework.messaging.handler.annotation.ValueConstants;
import org.springframework.messaging.simp.handler.AnnotationMethodMessageHandler;
-import java.util.Map;
-
/**
* Resolves method parameters annotated with {@link PathVariable @PathVariable}.
*
@@ -40,8 +39,9 @@ import java.util.Map;
*/
public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
- public PathVariableMethodArgumentResolver(ConversionService cs, ConfigurableBeanFactory beanFactory) {
- super(cs, beanFactory);
+
+ public PathVariableMethodArgumentResolver(ConversionService cs) {
+ super(cs, null);
}
@Override
@@ -57,9 +57,10 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod
@Override
protected Object resolveArgumentInternal(MethodParameter parameter, Message> message, String name) throws Exception {
- Map
+ * For STOMP over WebSocket messages: this is the destination of the STOMP message
+ * (e.g. "/positions"). Ant-style path patterns (e.g. "/price.stock.*") are supported
+ * and so are path template variables (e.g. "/price.stock.{ticker}"").
*/
String[] value() default {};
diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/handler/AnnotationMethodMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/handler/AnnotationMethodMessageHandler.java
index 51d846124e..71f5765e38 100644
--- a/spring-messaging/src/main/java/org/springframework/messaging/simp/handler/AnnotationMethodMessageHandler.java
+++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/handler/AnnotationMethodMessageHandler.java
@@ -51,8 +51,8 @@ import org.springframework.messaging.handler.annotation.support.ExceptionHandler
import org.springframework.messaging.handler.annotation.support.HeaderMethodArgumentResolver;
import org.springframework.messaging.handler.annotation.support.HeadersMethodArgumentResolver;
import org.springframework.messaging.handler.annotation.support.MessageMethodArgumentResolver;
-import org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver;
import org.springframework.messaging.handler.annotation.support.PathVariableMethodArgumentResolver;
+import org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver;
import org.springframework.messaging.handler.method.HandlerMethod;
import org.springframework.messaging.handler.method.HandlerMethodArgumentResolver;
import org.springframework.messaging.handler.method.HandlerMethodArgumentResolverComposite;
@@ -70,7 +70,6 @@ import org.springframework.messaging.simp.annotation.support.PrincipalMethodArgu
import org.springframework.messaging.simp.annotation.support.SendToMethodReturnValueHandler;
import org.springframework.messaging.simp.annotation.support.SubscriptionMethodReturnValueHandler;
import org.springframework.messaging.support.MessageBuilder;
-import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.messaging.support.converter.ByteArrayMessageConverter;
import org.springframework.messaging.support.converter.CompositeMessageConverter;
import org.springframework.messaging.support.converter.MessageConverter;
@@ -85,18 +84,24 @@ import org.springframework.util.ReflectionUtils.MethodFilter;
/**
+ * A handler for messages that delegates to {@link SubscribeEvent @SubscribeEvent} and
+ * {@link MessageMapping @MessageMapping} annotated methods.
+ *
* @author Rossen Stoyanchev
* @author Brian Clozel
* @since 4.0
*/
public class AnnotationMethodMessageHandler implements MessageHandler, ApplicationContextAware, InitializingBean {
- public static final String PATH_TEMPLATE_VARIABLES_HEADER = "Spring-PathTemplateVariables";
+ public static final String PATH_TEMPLATE_VARIABLES_HEADER =
+ AnnotationMethodMessageHandler.class.getSimpleName() + ".templateVariables";
- public static final String BEST_MATCHING_PATTERN_HEADER = "Spring-BestMatchingPattern";
+ public static final String BEST_MATCHING_PATTERN_HEADER =
+ AnnotationMethodMessageHandler.class.getSimpleName() + ".bestMatchingPattern";
private static final Log logger = LogFactory.getLog(AnnotationMethodMessageHandler.class);
+
private final PathMatcher pathMatcher = new AntPathMatcher();
private final SimpMessageSendingOperations brokerTemplate;
@@ -255,7 +260,7 @@ public class AnnotationMethodMessageHandler implements MessageHandler, Applicati
// Annotation-based argument resolution
this.argumentResolvers.addResolver(new HeaderMethodArgumentResolver(this.conversionService, beanFactory));
this.argumentResolvers.addResolver(new HeadersMethodArgumentResolver());
- this.argumentResolvers.addResolver(new PathVariableMethodArgumentResolver(this.conversionService, beanFactory));
+ this.argumentResolvers.addResolver(new PathVariableMethodArgumentResolver(this.conversionService));
// Type-based argument resolution
this.argumentResolvers.addResolver(new PrincipalMethodArgumentResolver());
@@ -287,6 +292,9 @@ public class AnnotationMethodMessageHandler implements MessageHandler, Applicati
}
}
+ /**
+ * Whether the given bean type should be introspected for messaging handling methods.
+ */
protected boolean isHandler(Class> beanType) {
return (AnnotationUtils.findAnnotation(beanType, Controller.class) != null);
}
@@ -369,32 +377,33 @@ public class AnnotationMethodMessageHandler implements MessageHandler, Applicati
}
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.wrap(message);
- String lookupPath = getLookupPath(headers.getDestination());
- if (lookupPath == null) {
+ String destinationToMatch = getDestinationToMatch(headers.getDestination());
+ if (destinationToMatch == null) {
if (logger.isTraceEnabled()) {
- logger.trace("Ignoring message with destination " + headers.getDestination());
+ logger.trace("Ignoring message with destination=" + headers.getDestination());
}
return;
}
- MappingInfoMatch match = matchMappingInfo(lookupPath, handlerMethods);
+ Match match = getMatchingHandlerMethod(destinationToMatch, handlerMethods);
if (match == null) {
if (logger.isTraceEnabled()) {
- logger.trace("No matching method, lookup path " + lookupPath);
+ logger.trace("No matching handler method for destination=" + destinationToMatch);
}
return;
}
- HandlerMethod handlerMethod = match.handlerMethod.createWithResolvedBean();
+ String matchedPattern = match.getMatchedPattern();
+ HandlerMethod handlerMethod = match.getHandlerMethod().createWithResolvedBean();
InvocableHandlerMethod invocableHandlerMethod = new InvocableHandlerMethod(handlerMethod);
invocableHandlerMethod.setMessageMethodArgumentResolvers(this.argumentResolvers);
try {
- headers.setDestination(lookupPath);
- headers.setHeader(BEST_MATCHING_PATTERN_HEADER,match.mappingDestination);
- headers.setHeader(PATH_TEMPLATE_VARIABLES_HEADER,
- pathMatcher.extractUriTemplateVariables(match.mappingDestination,lookupPath));
+ headers.setDestination(destinationToMatch);
+ headers.setHeader(BEST_MATCHING_PATTERN_HEADER, matchedPattern);
+ Map