Browse Source

Placeholder support for STOMP @MessageMapping methods

Issue: SPR-13271
pull/849/head
Rossen Stoyanchev 11 years ago
parent
commit
4b4efa9f6e
  1. 34
      spring-messaging/src/main/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandler.java
  2. 47
      spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandlerTests.java

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -27,6 +27,7 @@ import java.util.Set; @@ -27,6 +27,7 @@ import java.util.Set;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.SmartLifecycle;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.ConversionService;
@ -69,6 +70,7 @@ import org.springframework.util.Assert; @@ -69,6 +70,7 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringValueResolver;
import org.springframework.validation.Validator;
/**
@ -82,7 +84,7 @@ import org.springframework.validation.Validator; @@ -82,7 +84,7 @@ import org.springframework.validation.Validator;
* @since 4.0
*/
public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHandler<SimpMessageMappingInfo>
implements SmartLifecycle {
implements EmbeddedValueResolverAware, SmartLifecycle {
private static final boolean completableFuturePresent = ClassUtils.isPresent("java.util.concurrent.CompletableFuture",
SimpAnnotationMethodMessageHandler.class.getClassLoader());
@ -104,6 +106,8 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan @@ -104,6 +106,8 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
private Validator validator;
private StringValueResolver valueResolver;
private MessageHeaderInitializer headerInitializer;
private final Object lifecycleMonitor = new Object();
@ -234,6 +238,11 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan @@ -234,6 +238,11 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
this.validator = validator;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.valueResolver = resolver;
}
/**
* Configure a {@link MessageHeaderInitializer} to pass on to
* {@link org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler}s
@ -376,13 +385,30 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan @@ -376,13 +385,30 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
}
private SimpMessageMappingInfo createMessageMappingCondition(MessageMapping annotation) {
String[] destinations = resolveEmbeddedValuesInDestinations(annotation.value());
return new SimpMessageMappingInfo(SimpMessageTypeMessageCondition.MESSAGE,
new DestinationPatternsMessageCondition(annotation.value(), this.pathMatcher));
new DestinationPatternsMessageCondition(destinations, this.pathMatcher));
}
private SimpMessageMappingInfo createSubscribeCondition(SubscribeMapping annotation) {
String[] destinations = resolveEmbeddedValuesInDestinations(annotation.value());
return new SimpMessageMappingInfo(SimpMessageTypeMessageCondition.SUBSCRIBE,
new DestinationPatternsMessageCondition(annotation.value(), this.pathMatcher));
new DestinationPatternsMessageCondition(destinations, this.pathMatcher));
}
/**
* Resolve placeholder values in the given array of destinations.
* @return a new array with updated destinations
*/
protected String[] resolveEmbeddedValuesInDestinations(String[] destinations) {
if (this.valueResolver == null) {
return destinations;
}
String[] result = new String[destinations.length];
for (int i = 0; i < destinations.length; i++) {
result[i] = this.valueResolver.resolveStringValue(destinations[i]);
}
return result;
}
@Override

47
spring-messaging/src/test/java/org/springframework/messaging/simp/annotation/support/SimpAnnotationMethodMessageHandlerTests.java

@ -28,11 +28,9 @@ import java.util.concurrent.ConcurrentHashMap; @@ -28,11 +28,9 @@ import java.util.concurrent.ConcurrentHashMap;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import static org.mockito.BDDMockito.given;
import org.mockito.Captor;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.messaging.Message;
@ -62,10 +60,16 @@ import org.springframework.validation.Errors; @@ -62,10 +60,16 @@ import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Mockito.verify;
import org.mockito.MockitoAnnotations;
/**
* Test fixture for
@ -107,8 +111,7 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -107,8 +111,7 @@ public class SimpAnnotationMethodMessageHandlerTests {
this.messageHandler.setValidator(new StringTestValidator(TEST_INVALID_VALUE));
this.messageHandler.afterPropertiesSet();
testController = new TestController();
this.messageHandler.registerHandler(this.testController);
this.testController = new TestController();
}
@ -117,6 +120,7 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -117,6 +120,7 @@ public class SimpAnnotationMethodMessageHandlerTests {
public void headerArgumentResolution() {
Map<String, Object> headers = Collections.singletonMap("foo", "bar");
Message<?> message = createMessage("/pre/headers", headers);
this.messageHandler.registerHandler(this.testController);
this.messageHandler.handleMessage(message);
assertEquals("headers", this.testController.method);
@ -128,6 +132,7 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -128,6 +132,7 @@ public class SimpAnnotationMethodMessageHandlerTests {
public void optionalHeaderArgumentResolutionWhenPresent() {
Map<String, Object> headers = Collections.singletonMap("foo", "bar");
Message<?> message = createMessage("/pre/optionalHeaders", headers);
this.messageHandler.registerHandler(this.testController);
this.messageHandler.handleMessage(message);
assertEquals("optionalHeaders", this.testController.method);
@ -138,6 +143,7 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -138,6 +143,7 @@ public class SimpAnnotationMethodMessageHandlerTests {
@Test
public void optionalHeaderArgumentResolutionWhenNotPresent() {
Message<?> message = createMessage("/pre/optionalHeaders");
this.messageHandler.registerHandler(this.testController);
this.messageHandler.handleMessage(message);
assertEquals("optionalHeaders", this.testController.method);
@ -148,6 +154,7 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -148,6 +154,7 @@ public class SimpAnnotationMethodMessageHandlerTests {
@Test
public void messageMappingDestinationVariableResolution() {
Message<?> message = createMessage("/pre/message/bar/value");
this.messageHandler.registerHandler(this.testController);
this.messageHandler.handleMessage(message);
assertEquals("messageMappingDestinationVariable", this.testController.method);
@ -158,6 +165,7 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -158,6 +165,7 @@ public class SimpAnnotationMethodMessageHandlerTests {
@Test
public void subscribeEventDestinationVariableResolution() {
Message<?> message = createMessage("/pre/sub/bar/value");
this.messageHandler.registerHandler(this.testController);
this.messageHandler.handleMessage(message);
assertEquals("subscribeEventDestinationVariable", this.testController.method);
@ -168,6 +176,7 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -168,6 +176,7 @@ public class SimpAnnotationMethodMessageHandlerTests {
@Test
public void simpleBinding() {
Message<?> message = createMessage("/pre/binding/id/12");
this.messageHandler.registerHandler(this.testController);
this.messageHandler.handleMessage(message);
assertEquals("simpleBinding", this.testController.method);
@ -178,13 +187,16 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -178,13 +187,16 @@ public class SimpAnnotationMethodMessageHandlerTests {
@Test
public void validationError() {
Message<?> message = createMessage("/pre/validation/payload");
this.messageHandler.registerHandler(this.testController);
this.messageHandler.handleMessage(message);
assertEquals("handleValidationException", this.testController.method);
}
@Test
public void exceptionWithHandlerMethodArg() {
Message<?> message = createMessage("/pre/illegalState");
this.messageHandler.registerHandler(this.testController);
this.messageHandler.handleMessage(message);
assertEquals("handleExceptionWithHandlerMethodArg", this.testController.method);
@ -203,6 +215,7 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -203,6 +215,7 @@ public class SimpAnnotationMethodMessageHandlerTests {
headers.setSessionAttributes(sessionAttributes);
headers.setDestination("/pre/scope");
Message<?> message = MessageBuilder.withPayload(new byte[0]).setHeaders(headers).build();
this.messageHandler.registerHandler(this.testController);
this.messageHandler.handleMessage(message);
assertEquals("scope", this.testController.method);
@ -217,6 +230,7 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -217,6 +230,7 @@ public class SimpAnnotationMethodMessageHandlerTests {
this.messageHandler.setDestinationPrefixes(Arrays.asList("/app1", "/app2/"));
Message<?> message = createMessage("/app1/pre.foo");
this.messageHandler.registerHandler(this.testController);
this.messageHandler.handleMessage(message);
assertEquals("handleFoo", controller.method);
@ -234,7 +248,6 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -234,7 +248,6 @@ public class SimpAnnotationMethodMessageHandlerTests {
given(this.channel.send(any(Message.class))).willReturn(true);
given(this.converter.toMessage(anyObject(), any(MessageHeaders.class))).willReturn(emptyMessage);
ListenableFutureController controller = new ListenableFutureController();
this.messageHandler.registerHandler(controller);
this.messageHandler.setDestinationPrefixes(Arrays.asList("/app1", "/app2/"));
@ -304,6 +317,17 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -304,6 +317,17 @@ public class SimpAnnotationMethodMessageHandlerTests {
assertTrue(controller.exceptionCaught);
}
@Test
public void placeholder() throws Exception {
Message<?> message = createMessage("/pre/myValue");
this.messageHandler.setEmbeddedValueResolver(value -> ("/${myProperty}".equals(value) ? "/myValue" : value));
this.messageHandler.registerHandler(this.testController);
this.messageHandler.handleMessage(message);
assertEquals("placeholder", this.testController.method);
}
private Message<?> createMessage(String destination) {
return createMessage(destination, null);
}
@ -409,6 +433,11 @@ public class SimpAnnotationMethodMessageHandlerTests { @@ -409,6 +433,11 @@ public class SimpAnnotationMethodMessageHandlerTests {
assertThat(simpAttributes.getAttribute("name"), is("value"));
this.method = "scope";
}
@MessageMapping("/${myProperty}")
public void placeholder() {
this.method = "placeholder";
}
}
@Controller

Loading…
Cancel
Save