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/DestinationVariable.java similarity index 77% rename from spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/PathVariable.java rename to spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/DestinationVariable.java index 9d50286c2cf..ad52177120d 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/DestinationVariable.java @@ -23,26 +23,26 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * 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. + * Annotation that indicates a method parameter should be bound to a template variable + * in a destination template string. Supported on message handling methods such as + * {@link MessageMapping @MessageMapping}. + *

+ * A {@code @DestinationVariable} template variable is always required. * * @author Brian Clozel + * @author Rossen Stoyanchev * @since 4.0 + * * @see org.springframework.messaging.handler.annotation.MessageMapping * @see org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler */ @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) @Documented -public @interface PathVariable { +public @interface DestinationVariable { /** - * The path template variable to bind to. + * The name of the destination template variable to bind to. */ String value() default ""; 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 01c26491a8c..9da9e0788ea 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 @@ -53,8 +53,8 @@ import org.springframework.messaging.Message; * with STOMP over WebSocket support also sub-classes such as * {@link org.springframework.messaging.simp.SimpMessageHeaderAccessor} * for convenient access to all method arguments. - *

  • {@link PathVariable}-annotated arguments for access to URI variable - * values extracted from the message destination (i.e. /hotels/{hotel}). + *
  • {@link DestinationVariable}-annotated arguments for access to template + * variable values extracted from the message destination (e.g. /hotels/{hotel}). * Variable values will be converted to the declared method argument type.
  • *
  • {@link java.security.Principal} method arguments are supported with * STOMP over WebSocket messages. It reflects the user logged in to the 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/DestinationVariableMethodArgumentResolver.java similarity index 59% rename from spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/PathVariableMethodArgumentResolver.java rename to spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolver.java index f0cd93c6490..9ebd81363ae 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/DestinationVariableMethodArgumentResolver.java @@ -22,46 +22,45 @@ import org.springframework.core.MethodParameter; import org.springframework.core.convert.ConversionService; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandlingException; -import org.springframework.messaging.handler.annotation.PathVariable; +import org.springframework.messaging.handler.annotation.DestinationVariable; import org.springframework.messaging.handler.annotation.ValueConstants; /** - * Resolves method parameters annotated with {@link PathVariable @PathVariable}. - * - *

    A @{@link PathVariable} is a named value that gets resolved from a path - * template variable that matches the Message destination header. - * It is always required and does not have a default value to fall back on. + * Resolves method parameters annotated with + * {@link org.springframework.messaging.handler.annotation.DestinationVariable @DestinationVariable}. * * @author Brian Clozel - * @see org.springframework.messaging.handler.annotation.PathVariable - * @see org.springframework.messaging.MessageHeaders * @since 4.0 */ -public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { +public class DestinationVariableMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver { - public static final String PATH_TEMPLATE_VARIABLES_HEADER = - PathVariableMethodArgumentResolver.class.getSimpleName() + ".templateVariables"; + public static final String DESTINATION_TEMPLATE_VARIABLES_HEADER = + DestinationVariableMethodArgumentResolver.class.getSimpleName() + ".templateVariables"; - public PathVariableMethodArgumentResolver(ConversionService cs) { + public DestinationVariableMethodArgumentResolver(ConversionService cs) { super(cs, null); } @Override public boolean supportsParameter(MethodParameter parameter) { - return parameter.hasParameterAnnotation(PathVariable.class); + return parameter.hasParameterAnnotation(DestinationVariable.class); } @Override protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) { - PathVariable annotation = parameter.getParameterAnnotation(PathVariable.class); - return new PathVariableNamedValueInfo(annotation); + DestinationVariable annotation = parameter.getParameterAnnotation(DestinationVariable.class); + return new DestinationVariableNamedValueInfo(annotation); } @Override - protected Object resolveArgumentInternal(MethodParameter parameter, Message message, String name) throws Exception { + protected Object resolveArgumentInternal(MethodParameter parameter, Message message, String name) + throws Exception { + @SuppressWarnings("unchecked") - Map vars = (Map) message.getHeaders().get(PATH_TEMPLATE_VARIABLES_HEADER); + Map vars = (Map) message.getHeaders().get( + DESTINATION_TEMPLATE_VARIABLES_HEADER); + return (vars != null) ? vars.get(name) : null; } @@ -72,9 +71,9 @@ public class PathVariableMethodArgumentResolver extends AbstractNamedValueMethod } - private static class PathVariableNamedValueInfo extends NamedValueInfo { + private static class DestinationVariableNamedValueInfo extends NamedValueInfo { - private PathVariableNamedValueInfo(PathVariable annotation) { + private DestinationVariableNamedValueInfo(DestinationVariable annotation) { super(annotation.value(), true, ValueConstants.DEFAULT_NONE); } } 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 0db464ba71d..1a3ed620a6b 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 @@ -41,12 +41,8 @@ import org.springframework.messaging.converter.StringMessageConverter; import org.springframework.messaging.core.AbstractMessageSendingTemplate; import org.springframework.messaging.handler.HandlerMethod; import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.handler.annotation.support.AnnotationExceptionHandlerMethodResolver; -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.PathVariableMethodArgumentResolver; -import org.springframework.messaging.handler.annotation.support.PayloadArgumentResolver; +import org.springframework.messaging.handler.annotation.support.*; +import org.springframework.messaging.handler.annotation.support.DestinationVariableMethodArgumentResolver; import org.springframework.messaging.handler.invocation.AbstractExceptionHandlerMethodResolver; import org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler; import org.springframework.messaging.handler.DestinationPatternsMessageCondition; @@ -66,10 +62,11 @@ import org.springframework.util.ClassUtils; import org.springframework.util.PathMatcher; /** - * A handler for messages delegating to {@link org.springframework.messaging.simp.annotation.SubscribeMapping @SubscribeMapping} and + * A handler for messages delegating to + * {@link org.springframework.messaging.simp.annotation.SubscribeMapping @SubscribeMapping} and * {@link MessageMapping @MessageMapping} annotated methods. *

    - * Supports Ant-style path patterns as well as URI template variables in destinations. + * Supports Ant-style path patterns with template variables. * * @author Rossen Stoyanchev * @author Brian Clozel @@ -226,7 +223,7 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan // Annotation-based argument resolution resolvers.add(new HeaderMethodArgumentResolver(this.conversionService, beanFactory)); resolvers.add(new HeadersMethodArgumentResolver()); - resolvers.add(new PathVariableMethodArgumentResolver(this.conversionService)); + resolvers.add(new DestinationVariableMethodArgumentResolver(this.conversionService)); // Type-based argument resolution resolvers.add(new PrincipalMethodArgumentResolver()); @@ -339,7 +336,7 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan Map vars = getPathMatcher().extractUriTemplateVariables(matchedPattern, lookupDestination); headers.setDestination(lookupDestination); - headers.setHeader(PathVariableMethodArgumentResolver.PATH_TEMPLATE_VARIABLES_HEADER, vars); + headers.setHeader(DestinationVariableMethodArgumentResolver.DESTINATION_TEMPLATE_VARIABLES_HEADER, vars); message = MessageBuilder.withPayload(message.getPayload()).setHeaders(headers).build(); super.handleMatch(mapping, handlerMethod, lookupDestination, message); diff --git a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/PathVariableMethodArgumentResolverTests.java b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolverTests.java similarity index 77% rename from spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/PathVariableMethodArgumentResolverTests.java rename to spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolverTests.java index 42f8b5a59d7..012a1ee3fe6 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/PathVariableMethodArgumentResolverTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/DestinationVariableMethodArgumentResolverTests.java @@ -29,18 +29,19 @@ import org.springframework.core.MethodParameter; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandlingException; -import org.springframework.messaging.handler.annotation.PathVariable; +import org.springframework.messaging.handler.annotation.DestinationVariable; import org.springframework.messaging.support.MessageBuilder; import static org.junit.Assert.*; /** - * Test fixture for {@link PathVariableMethodArgumentResolver} tests. + * Test fixture for {@link DestinationVariableMethodArgumentResolver} tests. + * * @author Brian Clozel */ -public class PathVariableMethodArgumentResolverTests { +public class DestinationVariableMethodArgumentResolverTests { - private PathVariableMethodArgumentResolver resolver; + private DestinationVariableMethodArgumentResolver resolver; private MethodParameter paramAnnotated; private MethodParameter paramAnnotatedValue; @@ -49,7 +50,7 @@ public class PathVariableMethodArgumentResolverTests { @Before public void setup() throws Exception { - this.resolver = new PathVariableMethodArgumentResolver(new DefaultConversionService()); + this.resolver = new DestinationVariableMethodArgumentResolver(new DefaultConversionService()); Method method = getClass().getDeclaredMethod("handleMessage", String.class, String.class, String.class); this.paramAnnotated = new MethodParameter(method, 0); @@ -57,9 +58,9 @@ public class PathVariableMethodArgumentResolverTests { this.paramNotAnnotated = new MethodParameter(method, 2); this.paramAnnotated.initParameterNameDiscovery(new DefaultParameterNameDiscoverer()); - GenericTypeResolver.resolveParameterType(this.paramAnnotated, PathVariableMethodArgumentResolver.class); + GenericTypeResolver.resolveParameterType(this.paramAnnotated, DestinationVariableMethodArgumentResolver.class); this.paramAnnotatedValue.initParameterNameDiscovery(new DefaultParameterNameDiscoverer()); - GenericTypeResolver.resolveParameterType(this.paramAnnotatedValue, PathVariableMethodArgumentResolver.class); + GenericTypeResolver.resolveParameterType(this.paramAnnotatedValue, DestinationVariableMethodArgumentResolver.class); } @Test @@ -71,13 +72,17 @@ public class PathVariableMethodArgumentResolverTests { @Test public void resolveArgument() throws Exception { - Map pathParams = new HashMap(); - pathParams.put("foo", "bar"); - pathParams.put("name", "value"); + + Map vars = new HashMap(); + vars.put("foo", "bar"); + vars.put("name", "value"); + Message message = MessageBuilder.withPayload(new byte[0]).setHeader( - PathVariableMethodArgumentResolver.PATH_TEMPLATE_VARIABLES_HEADER, pathParams).build(); + DestinationVariableMethodArgumentResolver.DESTINATION_TEMPLATE_VARIABLES_HEADER, vars).build(); + Object result = this.resolver.resolveArgument(this.paramAnnotated, message); assertEquals("bar", result); + result = this.resolver.resolveArgument(this.paramAnnotatedValue, message); assertEquals("value", result); } @@ -89,6 +94,10 @@ public class PathVariableMethodArgumentResolverTests { } @SuppressWarnings("unused") - private void handleMessage(@PathVariable String foo, @PathVariable(value = "name") String param1, String param3) { + private void handleMessage( + @DestinationVariable String foo, + @DestinationVariable(value = "name") String param1, + String param3) { } + } \ No newline at end of file diff --git a/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandlerTests.java b/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandlerTests.java index 5de81368357..043b3d0b85c 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandlerTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandlerTests.java @@ -26,17 +26,16 @@ import org.springframework.context.support.StaticApplicationContext; import org.springframework.messaging.Message; import org.springframework.messaging.MessageChannel; import org.springframework.messaging.SubscribableChannel; +import org.springframework.messaging.handler.annotation.DestinationVariable; import org.springframework.messaging.handler.annotation.Header; import org.springframework.messaging.handler.annotation.Headers; import org.springframework.messaging.handler.annotation.MessageMapping; -import org.springframework.messaging.handler.annotation.PathVariable; import org.springframework.messaging.simp.SimpMessageHeaderAccessor; import org.springframework.messaging.simp.SimpMessageSendingOperations; import org.springframework.messaging.simp.SimpMessageType; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.messaging.simp.annotation.SubscribeMapping; import org.springframework.messaging.support.MessageBuilder; -import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler; import org.springframework.stereotype.Controller; import static org.junit.Assert.*; @@ -86,26 +85,26 @@ public class SimpAnnotationMethodMessageHandlerTests { } @Test - public void messageMappingPathVariableResolution() { + public void messageMappingDestinationVariableResolution() { SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(); headers.setDestination("/pre/message/bar/value"); Message message = MessageBuilder.withPayload(new byte[0]).setHeaders(headers).build(); this.messageHandler.handleMessage(message); - assertEquals("messageMappingPathVariable", this.testController.method); + assertEquals("messageMappingDestinationVariable", this.testController.method); assertEquals("bar", this.testController.arguments.get("foo")); assertEquals("value", this.testController.arguments.get("name")); } @Test - public void subscribeEventPathVariableResolution() { + public void subscribeEventDestinationVariableResolution() { SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.SUBSCRIBE); headers.setDestination("/pre/sub/bar/value"); Message message = MessageBuilder.withPayload(new byte[0]) .copyHeaders(headers.toMap()).build(); this.messageHandler.handleMessage(message); - assertEquals("subscribeEventPathVariable", this.testController.method); + assertEquals("subscribeEventDestinationVariable", this.testController.method); assertEquals("bar", this.testController.arguments.get("foo")); assertEquals("value", this.testController.arguments.get("name")); } @@ -175,17 +174,17 @@ public class SimpAnnotationMethodMessageHandlerTests { } @MessageMapping("/message/{foo}/{name}") - public void messageMappingPathVariable(@PathVariable("foo") String param1, - @PathVariable("name") String param2) { - this.method = "messageMappingPathVariable"; + public void messageMappingDestinationVariable(@DestinationVariable("foo") String param1, + @DestinationVariable("name") String param2) { + this.method = "messageMappingDestinationVariable"; this.arguments.put("foo", param1); this.arguments.put("name", param2); } @SubscribeMapping("/sub/{foo}/{name}") - public void subscribeEventPathVariable(@PathVariable("foo") String param1, - @PathVariable("name") String param2) { - this.method = "subscribeEventPathVariable"; + public void subscribeEventDestinationVariable(@DestinationVariable("foo") String param1, + @DestinationVariable("name") String param2) { + this.method = "subscribeEventDestinationVariable"; this.arguments.put("foo", param1); this.arguments.put("name", param2); } @@ -196,7 +195,7 @@ public class SimpAnnotationMethodMessageHandlerTests { } @MessageMapping("/bestmatch/{foo}/path") - public void bestMatch(@PathVariable("foo") String param1) { + public void bestMatch(@DestinationVariable("foo") String param1) { this.method = "bestMatch"; this.arguments.put("foo", param1); } @@ -207,7 +206,7 @@ public class SimpAnnotationMethodMessageHandlerTests { } @MessageMapping("/binding/id/{id}") - public void simpleBinding(@PathVariable("id") Long id) { + public void simpleBinding(@DestinationVariable("id") Long id) { this.method = "simpleBinding"; this.arguments.put("id", id); }