|
25 | 25 | import org.hamcrest.Matchers;
|
26 | 26 | import org.junit.Test;
|
27 | 27 |
|
28 |
| -import org.springframework.beans.DirectFieldAccessor; |
29 | 28 | import org.springframework.context.ApplicationContext;
|
30 | 29 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
31 | 30 | import org.springframework.context.annotation.Bean;
|
32 | 31 | import org.springframework.context.annotation.Configuration;
|
33 | 32 | import org.springframework.context.support.StaticApplicationContext;
|
34 | 33 | import org.springframework.messaging.Message;
|
| 34 | +import org.springframework.messaging.MessageChannel; |
35 | 35 | import org.springframework.messaging.MessageHandler;
|
36 | 36 | import org.springframework.messaging.converter.ByteArrayMessageConverter;
|
37 | 37 | import org.springframework.messaging.converter.CompositeMessageConverter;
|
|
44 | 44 | import org.springframework.messaging.handler.annotation.SendTo;
|
45 | 45 | import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
|
46 | 46 | import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
|
| 47 | +import org.springframework.messaging.simp.SimpMessageHeaderAccessor; |
47 | 48 | import org.springframework.messaging.simp.SimpMessageType;
|
| 49 | +import org.springframework.messaging.simp.SimpMessagingTemplate; |
48 | 50 | import org.springframework.messaging.simp.annotation.SubscribeMapping;
|
49 | 51 | import org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler;
|
50 | 52 | import org.springframework.messaging.simp.broker.DefaultSubscriptionRegistry;
|
|
66 | 68 | import org.springframework.stereotype.Controller;
|
67 | 69 | import org.springframework.util.AntPathMatcher;
|
68 | 70 | import org.springframework.util.MimeTypeUtils;
|
| 71 | +import org.springframework.util.PathMatcher; |
69 | 72 | import org.springframework.validation.Errors;
|
70 | 73 | import org.springframework.validation.Validator;
|
71 | 74 | import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;
|
@@ -412,7 +415,7 @@ public void customPathMatcher() {
|
412 | 415 |
|
413 | 416 | DefaultUserDestinationResolver resolver = context.getBean(DefaultUserDestinationResolver.class);
|
414 | 417 | assertNotNull(resolver);
|
415 |
| - assertEquals(false, new DirectFieldAccessor(resolver).getPropertyValue("keepLeadingSlash")); |
| 418 | + assertEquals(false, resolver.isRemoveLeadingSlash()); |
416 | 419 | }
|
417 | 420 |
|
418 | 421 | @Test
|
@@ -460,6 +463,67 @@ public void userBroadcastsDisabledWithSimpleBroker() {
|
460 | 463 | assertNotEquals(UserRegistryMessageHandler.class, messageHandler.getClass());
|
461 | 464 | }
|
462 | 465 |
|
| 466 | + @Test // SPR-16275 |
| 467 | + public void dotSeparatorWithBrokerSlashConvention() { |
| 468 | + ApplicationContext context = loadConfig(DotSeparatorWithSlashBrokerConventionConfig.class); |
| 469 | + testDotSeparator(context, true); |
| 470 | + } |
| 471 | + |
| 472 | + @Test // SPR-16275 |
| 473 | + public void dotSeparatorWithBrokerDotConvention() { |
| 474 | + ApplicationContext context = loadConfig(DotSeparatorWithDotBrokerConventionConfig.class); |
| 475 | + testDotSeparator(context, false); |
| 476 | + } |
| 477 | + |
| 478 | + private void testDotSeparator(ApplicationContext context, boolean expectLeadingSlash) { |
| 479 | + MessageChannel inChannel = context.getBean("clientInboundChannel", MessageChannel.class); |
| 480 | + TestChannel outChannel = context.getBean("clientOutboundChannel", TestChannel.class); |
| 481 | + MessageChannel brokerChannel = context.getBean("brokerChannel", MessageChannel.class); |
| 482 | + |
| 483 | + |
| 484 | + // 1. Subscribe to user destination |
| 485 | + |
| 486 | + StompHeaderAccessor headers = StompHeaderAccessor.create(StompCommand.SUBSCRIBE); |
| 487 | + headers.setSessionId("sess1"); |
| 488 | + headers.setSubscriptionId("subs1"); |
| 489 | + headers.setDestination("/user/queue.q1"); |
| 490 | + Message<?> message = MessageBuilder.createMessage(new byte[0], headers.getMessageHeaders()); |
| 491 | + inChannel.send(message); |
| 492 | + |
| 493 | + // 2. Send message to user via inboundChannel |
| 494 | + |
| 495 | + headers = StompHeaderAccessor.create(StompCommand.SEND); |
| 496 | + headers.setSessionId("sess1"); |
| 497 | + headers.setDestination("/user/sess1/queue.q1"); |
| 498 | + message = MessageBuilder.createMessage("123".getBytes(), headers.getMessageHeaders()); |
| 499 | + inChannel.send(message); |
| 500 | + |
| 501 | + assertEquals(1, outChannel.messages.size()); |
| 502 | + Message<?> outputMessage = outChannel.messages.remove(0); |
| 503 | + headers = StompHeaderAccessor.wrap(outputMessage); |
| 504 | + |
| 505 | + assertEquals(SimpMessageType.MESSAGE, headers.getMessageType()); |
| 506 | + assertEquals(expectLeadingSlash ? "/queue.q1-usersess1" : "queue.q1-usersess1", headers.getDestination()); |
| 507 | + assertEquals("123", new String((byte[]) outputMessage.getPayload())); |
| 508 | + |
| 509 | + |
| 510 | + // 3. Send message via broker channel |
| 511 | + |
| 512 | + SimpMessagingTemplate template = new SimpMessagingTemplate(brokerChannel); |
| 513 | + SimpMessageHeaderAccessor accessor = SimpMessageHeaderAccessor.create(); |
| 514 | + accessor.setSessionId("sess1"); |
| 515 | + template.convertAndSendToUser("sess1", "queue.q1", "456".getBytes(), accessor.getMessageHeaders()); |
| 516 | + |
| 517 | + assertEquals(1, outChannel.messages.size()); |
| 518 | + outputMessage = outChannel.messages.remove(0); |
| 519 | + headers = StompHeaderAccessor.wrap(outputMessage); |
| 520 | + |
| 521 | + assertEquals(SimpMessageType.MESSAGE, headers.getMessageType()); |
| 522 | + assertEquals(expectLeadingSlash ? "/queue.q1-usersess1" : "queue.q1-usersess1", headers.getDestination()); |
| 523 | + assertEquals("456", new String((byte[]) outputMessage.getPayload())); |
| 524 | + |
| 525 | + } |
| 526 | + |
463 | 527 | private AnnotationConfigApplicationContext loadConfig(Class<?> configClass) {
|
464 | 528 | return new AnnotationConfigApplicationContext(configClass);
|
465 | 529 | }
|
@@ -575,6 +639,60 @@ protected void configureMessageBroker(MessageBrokerRegistry registry) {
|
575 | 639 | }
|
576 | 640 |
|
577 | 641 |
|
| 642 | + @Configuration |
| 643 | + static abstract class BaseDotSeparatorConfig extends BaseTestMessageBrokerConfig { |
| 644 | + |
| 645 | + @Override |
| 646 | + protected void configureMessageBroker(MessageBrokerRegistry registry) { |
| 647 | + registry.setPathMatcher(new AntPathMatcher(".")); |
| 648 | + } |
| 649 | + |
| 650 | + @Override |
| 651 | + @Bean |
| 652 | + public AbstractSubscribableChannel clientInboundChannel() { |
| 653 | + // synchronous |
| 654 | + return new ExecutorSubscribableChannel(null); |
| 655 | + } |
| 656 | + |
| 657 | + @Override |
| 658 | + @Bean |
| 659 | + public AbstractSubscribableChannel clientOutboundChannel() { |
| 660 | + return new TestChannel(); |
| 661 | + } |
| 662 | + |
| 663 | + @Override |
| 664 | + @Bean |
| 665 | + public AbstractSubscribableChannel brokerChannel() { |
| 666 | + // synchronous |
| 667 | + return new ExecutorSubscribableChannel(null); |
| 668 | + } |
| 669 | + } |
| 670 | + |
| 671 | + @Configuration |
| 672 | + static class DotSeparatorWithSlashBrokerConventionConfig extends BaseDotSeparatorConfig { |
| 673 | + |
| 674 | + // RabbitMQ-style broker convention for STOMP destinations |
| 675 | + |
| 676 | + @Override |
| 677 | + protected void configureMessageBroker(MessageBrokerRegistry registry) { |
| 678 | + super.configureMessageBroker(registry); |
| 679 | + registry.enableSimpleBroker("/topic", "/queue"); |
| 680 | + } |
| 681 | + } |
| 682 | + |
| 683 | + @Configuration |
| 684 | + static class DotSeparatorWithDotBrokerConventionConfig extends BaseDotSeparatorConfig { |
| 685 | + |
| 686 | + // Artemis-style broker convention for STOMP destinations |
| 687 | + |
| 688 | + @Override |
| 689 | + protected void configureMessageBroker(MessageBrokerRegistry registry) { |
| 690 | + super.configureMessageBroker(registry); |
| 691 | + registry.enableSimpleBroker("topic.", "queue."); |
| 692 | + } |
| 693 | + } |
| 694 | + |
| 695 | + |
578 | 696 | private static class TestChannel extends ExecutorSubscribableChannel {
|
579 | 697 |
|
580 | 698 | private final List<Message<?>> messages = new ArrayList<>();
|
|
0 commit comments