Polishing

This commit is contained in:
Juergen Hoeller 2015-07-30 00:08:36 +02:00
parent b35103cc5c
commit b1d6ae77e1
5 changed files with 41 additions and 43 deletions

View File

@ -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.
@ -22,10 +22,11 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.messaging.Message;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.util.ClassUtils;
/**
* A {@link HandlerMethodArgumentResolver} for {@link Message} parameters. Validates
* that the generic type of the payload matches with the message value.
* A {@link HandlerMethodArgumentResolver} for {@link Message} parameters.
* Validates that the generic type of the payload matches with the message value.
*
* @author Rossen Stoyanchev
* @author Stephane Nicoll
@ -33,7 +34,6 @@ import org.springframework.messaging.handler.invocation.HandlerMethodArgumentRes
*/
public class MessageMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return Message.class.isAssignableFrom(parameter.getParameterType());
@ -41,22 +41,19 @@ public class MessageMethodArgumentResolver implements HandlerMethodArgumentResol
@Override
public Object resolveArgument(MethodParameter parameter, Message<?> message) throws Exception {
Class<?> paramType = parameter.getParameterType();
if (!paramType.isAssignableFrom(message.getClass())) {
throw new MethodArgumentTypeMismatchException(message, parameter,
"The actual message type [" + message.getClass().getName() + "] " +
"does not match the expected type [" + paramType.getName() + "]");
"The actual message type [" + ClassUtils.getQualifiedName(message.getClass()) + "] " +
"does not match the expected type [" + ClassUtils.getQualifiedName(paramType) + "]");
}
Class<?> expectedPayloadType = getPayloadType(parameter);
Object payload = message.getPayload();
if (expectedPayloadType != null && !expectedPayloadType.isInstance(payload)) {
if (payload != null && expectedPayloadType != null && !expectedPayloadType.isInstance(payload)) {
throw new MethodArgumentTypeMismatchException(message, parameter,
"The expected Message<?> payload type [" + expectedPayloadType.getName() +
"] does not match the actual payload type [" + payload.getClass().getName() + "]");
"The expected Message<?> payload type [" + ClassUtils.getQualifiedName(expectedPayloadType) +
"] does not match the actual payload type [" + ClassUtils.getQualifiedName(payload.getClass()) + "]");
}
return message;

View File

@ -40,16 +40,16 @@ import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.util.PropertyPlaceholderHelper.PlaceholderResolver;
import org.springframework.util.StringUtils;
/**
* A {@link HandlerMethodReturnValueHandler} for sending to destinations specified in a
* {@link SendTo} or {@link SendToUser} method-level annotations.
*
* <p>The value returned from the method is converted, and turned to a {@link Message} and
* sent through the provided {@link MessageChannel}. The
* message is then enriched with the sessionId of the input message as well as the
* destination from the annotation(s). If multiple destinations are specified, a copy of
* the message is sent to each destination.
* sent through the provided {@link MessageChannel}. The message is then enriched with the
* session id of the input message as well as the destination from the annotation(s).
* If multiple destinations are specified, a copy of the message is sent to each destination.
*
* @author Rossen Stoyanchev
* @author Sebastien Deleuze
@ -116,7 +116,6 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
/**
* Configure a {@link MessageHeaderInitializer} to apply to the headers of all
* messages sent to the client outbound channel.
*
* <p>By default this property is not set.
*/
public void setHeaderInitializer(MessageHeaderInitializer headerInitializer) {
@ -133,8 +132,8 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
@Override
public boolean supportsReturnType(MethodParameter returnType) {
if ((returnType.getMethodAnnotation(SendTo.class) != null) ||
(returnType.getMethodAnnotation(SendToUser.class) != null)) {
if (returnType.getMethodAnnotation(SendTo.class) != null ||
returnType.getMethodAnnotation(SendToUser.class) != null) {
return true;
}
return (!this.annotationRequired);
@ -164,10 +163,12 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
for (String destination : destinations) {
destination = this.placeholderHelper.replacePlaceholders(destination, varResolver);
if (broadcast) {
this.messagingTemplate.convertAndSendToUser(user, destination, returnValue, createHeaders(null, returnType));
this.messagingTemplate.convertAndSendToUser(
user, destination, returnValue, createHeaders(null, returnType));
}
else {
this.messagingTemplate.convertAndSendToUser(user, destination, returnValue, createHeaders(sessionId, returnType));
this.messagingTemplate.convertAndSendToUser(
user, destination, returnValue, createHeaders(sessionId, returnType));
}
}
}
@ -206,7 +207,9 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
}
String name = DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER;
String destination = (String) message.getHeaders().get(name);
Assert.hasText(destination, "No lookup destination header in " + message);
if (!StringUtils.hasText(destination)) {
throw new IllegalStateException("No lookup destination header in " + message);
}
return (destination.startsWith("/") ?
new String[] {defaultPrefix + destination} : new String[] {defaultPrefix + "/" + destination});
@ -231,11 +234,11 @@ public class SendToMethodReturnValueHandler implements HandlerMethodReturnValueH
return "SendToMethodReturnValueHandler [annotationRequired=" + annotationRequired + "]";
}
private static class DestinationVariablePlaceholderResolver implements PlaceholderResolver {
private final Map<String, String> vars;
public DestinationVariablePlaceholderResolver(Map<String, String> vars) {
this.vars = vars;
}

View File

@ -104,14 +104,16 @@ public class SubscriptionMethodReturnValueHandler implements HandlerMethodReturn
String sessionId = SimpMessageHeaderAccessor.getSessionId(headers);
String subscriptionId = SimpMessageHeaderAccessor.getSubscriptionId(headers);
Assert.state(subscriptionId != null,
"No subscriptionId in message=" + message + ", method=" + returnType.getMethod());
if (subscriptionId == null) {
throw new IllegalStateException(
"No subscriptionId in " + message + " returned by: " + returnType.getMethod());
}
if (logger.isDebugEnabled()) {
logger.debug("Reply to @SubscribeMapping: " + returnValue);
}
this.messagingTemplate.convertAndSend(destination, returnValue, createHeaders(sessionId, subscriptionId, returnType));
this.messagingTemplate.convertAndSend(
destination, returnValue, createHeaders(sessionId, subscriptionId, returnType));
}
private MessageHeaders createHeaders(String sessionId, String subscriptionId, MethodParameter returnType) {

View File

@ -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.
@ -145,6 +145,7 @@ public class MessageMethodArgumentResolverTests {
assertSame(message, this.resolver.resolveArgument(parameter, message));
}
@SuppressWarnings("unused")
private void handleMessage(
Message<?> wildcardPayload,

View File

@ -83,13 +83,12 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
@Override
protected Class<?>[] getAnnotatedConfigClasses() {
return new Class<?>[] { TestMessageBrokerConfiguration.class, TestMessageBrokerConfigurer.class };
return new Class<?>[] {TestMessageBrokerConfiguration.class, TestMessageBrokerConfigurer.class};
}
@Test
public void sendMessageToController() throws Exception {
TextMessage message = create(StompCommand.SEND).headers("destination:/app/simple").build();
WebSocketSession session = doHandshake(new TestClientWebSocketHandler(0, message), "/ws").get();
@ -104,10 +103,8 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
@Test
public void sendMessageToControllerAndReceiveReplyViaTopic() throws Exception {
TextMessage message1 = create(StompCommand.SUBSCRIBE)
.headers("id:subs1", "destination:/topic/increment").build();
TextMessage message2 = create(StompCommand.SEND)
.headers("destination:/app/increment").body("5").build();
@ -126,7 +123,6 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
@Test
public void sendMessageToBrokerAndReceiveReplyViaTopic() throws Exception {
TextMessage m1 = create(StompCommand.SUBSCRIBE).headers("id:subs1", "destination:/topic/foo").build();
TextMessage m2 = create(StompCommand.SEND).headers("destination:/topic/foo").body("5").build();
@ -148,7 +144,6 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
@Test
public void sendSubscribeToControllerAndReceiveReply() throws Exception {
String destHeader = "destination:/app/number";
TextMessage message = create(StompCommand.SUBSCRIBE).headers("id:subs1", destHeader).build();
@ -168,7 +163,6 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
@Test
public void handleExceptionAndSendToUser() throws Exception {
String destHeader = "destination:/user/queue/error";
TextMessage m1 = create(StompCommand.SUBSCRIBE).headers("id:subs1", destHeader).build();
TextMessage m2 = create(StompCommand.SEND).headers("destination:/app/exception").build();
@ -178,7 +172,6 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
try {
assertTrue(clientHandler.latch.await(2, TimeUnit.SECONDS));
String payload = clientHandler.actual.get(0).getPayload();
assertTrue(payload.startsWith("MESSAGE\n"));
assertTrue(payload.contains("destination:/user/queue/error\n"));
@ -191,10 +184,8 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
@Test
public void webSocketScope() throws Exception {
TextMessage message1 = create(StompCommand.SUBSCRIBE)
.headers("id:subs1", "destination:/topic/scopedBeanValue").build();
TextMessage message2 = create(StompCommand.SEND)
.headers("destination:/app/scopedBeanValue").build();
@ -203,7 +194,6 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
try {
assertTrue(clientHandler.latch.await(2, TimeUnit.SECONDS));
String payload = clientHandler.actual.get(0).getPayload();
assertTrue(payload.startsWith("MESSAGE\n"));
assertTrue(payload.contains("destination:/topic/scopedBeanValue\n"));
@ -221,6 +211,7 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
private @interface IntegrationTestController {
}
@IntegrationTestController
static class SimpleController {
@ -243,6 +234,7 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
}
}
@IntegrationTestController
static class IncrementController {
@ -257,6 +249,7 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
}
}
@IntegrationTestController
static class ScopedBeanController {
@ -279,6 +272,7 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
String getValue();
}
static class ScopedBeanImpl implements ScopedBean {
private final String value;
@ -304,7 +298,6 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
private final CountDownLatch latch;
public TestClientWebSocketHandler(int expectedNumberOfMessages, TextMessage... messagesToSend) {
this.messagesToSend = messagesToSend;
this.expected = expectedNumberOfMessages;
@ -325,6 +318,7 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
}
}
@Configuration
@ComponentScan(
basePackageClasses=StompWebSocketIntegrationTests.class,
@ -333,7 +327,7 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
static class TestMessageBrokerConfigurer extends AbstractWebSocketMessageBrokerConfigurer {
@Autowired
private HandshakeHandler handshakeHandler; // can't rely on classpath for server detection
private HandshakeHandler handshakeHandler; // can't rely on classpath for server detection
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
@ -353,19 +347,20 @@ public class StompWebSocketIntegrationTests extends AbstractWebSocketIntegration
}
}
@Configuration
static class TestMessageBrokerConfiguration extends DelegatingWebSocketMessageBrokerConfiguration {
@Override
@Bean
public AbstractSubscribableChannel clientInboundChannel() {
return new ExecutorSubscribableChannel(); // synchronous
return new ExecutorSubscribableChannel(); // synchronous
}
@Override
@Bean
public AbstractSubscribableChannel clientOutboundChannel() {
return new ExecutorSubscribableChannel(); // synchronous
return new ExecutorSubscribableChannel(); // synchronous
}
}