Support DestinationVariable on RSocket handlers
Prior to this commit, the pattern destination variables were not set in the message headers prior to calling the handler. In this case, the `DestinationVariableMethodArgumentResolver` could not get the destination variables from the message headers and resolve those as handler arguments. This commit mutates the message headers if the message destination contains patterns. Fixes gh-22776
This commit is contained in:
parent
a0826a20c3
commit
cd69a4a03b
|
@ -24,9 +24,12 @@ import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
@ -39,6 +42,7 @@ import org.springframework.lang.Nullable;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.handler.CompositeMessageCondition;
|
import org.springframework.messaging.handler.CompositeMessageCondition;
|
||||||
import org.springframework.messaging.handler.DestinationPatternsMessageCondition;
|
import org.springframework.messaging.handler.DestinationPatternsMessageCondition;
|
||||||
|
import org.springframework.messaging.handler.HandlerMethod;
|
||||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||||
import org.springframework.messaging.handler.annotation.support.AnnotationExceptionHandlerMethodResolver;
|
import org.springframework.messaging.handler.annotation.support.AnnotationExceptionHandlerMethodResolver;
|
||||||
import org.springframework.messaging.handler.invocation.AbstractExceptionHandlerMethodResolver;
|
import org.springframework.messaging.handler.invocation.AbstractExceptionHandlerMethodResolver;
|
||||||
|
@ -46,9 +50,11 @@ import org.springframework.messaging.handler.invocation.reactive.AbstractEncoder
|
||||||
import org.springframework.messaging.handler.invocation.reactive.AbstractMethodMessageHandler;
|
import org.springframework.messaging.handler.invocation.reactive.AbstractMethodMessageHandler;
|
||||||
import org.springframework.messaging.handler.invocation.reactive.HandlerMethodArgumentResolver;
|
import org.springframework.messaging.handler.invocation.reactive.HandlerMethodArgumentResolver;
|
||||||
import org.springframework.messaging.handler.invocation.reactive.HandlerMethodReturnValueHandler;
|
import org.springframework.messaging.handler.invocation.reactive.HandlerMethodReturnValueHandler;
|
||||||
|
import org.springframework.messaging.support.MessageHeaderAccessor;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.util.AntPathMatcher;
|
import org.springframework.util.AntPathMatcher;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.PathMatcher;
|
import org.springframework.util.PathMatcher;
|
||||||
import org.springframework.util.StringValueResolver;
|
import org.springframework.util.StringValueResolver;
|
||||||
import org.springframework.validation.Validator;
|
import org.springframework.validation.Validator;
|
||||||
|
@ -311,4 +317,19 @@ public class MessageMappingMessageHandler extends AbstractMethodMessageHandler<C
|
||||||
return new AnnotationExceptionHandlerMethodResolver(beanType);
|
return new AnnotationExceptionHandlerMethodResolver(beanType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Mono<Void> handleMatch(CompositeMessageCondition mapping, HandlerMethod handlerMethod, Message<?> message) {
|
||||||
|
Set<String> patterns = mapping.getCondition(DestinationPatternsMessageCondition.class).getPatterns();
|
||||||
|
if (!CollectionUtils.isEmpty(patterns)) {
|
||||||
|
String pattern = patterns.iterator().next();
|
||||||
|
String destination = getDestination(message);
|
||||||
|
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(pattern, destination);
|
||||||
|
if (!CollectionUtils.isEmpty(vars)) {
|
||||||
|
MessageHeaderAccessor mha = MessageHeaderAccessor.getAccessor(message, MessageHeaderAccessor.class);
|
||||||
|
Assert.state(mha != null && mha.isMutable(), "Mutable MessageHeaderAccessor required");
|
||||||
|
mha.setHeader(DestinationVariableMethodArgumentResolver.DESTINATION_TEMPLATE_VARIABLES_HEADER, vars);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.handleMatch(mapping, handlerMethod, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,7 +381,11 @@ public abstract class AbstractMethodMessageHandler<T>
|
||||||
// handleNoMatch would have been invoked already
|
// handleNoMatch would have been invoked already
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
}
|
}
|
||||||
HandlerMethod handlerMethod = match.getHandlerMethod().createWithResolvedBean();
|
return handleMatch(match.mapping, match.handlerMethod, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Mono<Void> handleMatch(T mapping, HandlerMethod handlerMethod, Message<?> message) {
|
||||||
|
handlerMethod = handlerMethod.createWithResolvedBean();
|
||||||
return this.invocableHelper.handleMessage(handlerMethod, message);
|
return this.invocableHelper.handleMessage(handlerMethod, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,6 +180,7 @@ class MessagingRSocket extends AbstractRSocket {
|
||||||
|
|
||||||
private MessageHeaders createHeaders(String destination, @Nullable MonoProcessor<?> replyMono) {
|
private MessageHeaders createHeaders(String destination, @Nullable MonoProcessor<?> replyMono) {
|
||||||
MessageHeaderAccessor headers = new MessageHeaderAccessor();
|
MessageHeaderAccessor headers = new MessageHeaderAccessor();
|
||||||
|
headers.setLeaveMutable(true);
|
||||||
headers.setHeader(DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER, destination);
|
headers.setHeader(DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER, destination);
|
||||||
if (this.dataMimeType != null) {
|
if (this.dataMimeType != null) {
|
||||||
headers.setContentType(this.dataMimeType);
|
headers.setContentType(this.dataMimeType);
|
||||||
|
|
|
@ -39,10 +39,13 @@ import org.springframework.core.io.buffer.DataBufferFactory;
|
||||||
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.handler.DestinationPatternsMessageCondition;
|
import org.springframework.messaging.handler.DestinationPatternsMessageCondition;
|
||||||
|
import org.springframework.messaging.handler.annotation.DestinationVariable;
|
||||||
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
|
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
|
||||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||||
import org.springframework.messaging.handler.invocation.reactive.TestEncoderMethodReturnValueHandler;
|
import org.springframework.messaging.handler.invocation.reactive.TestEncoderMethodReturnValueHandler;
|
||||||
import org.springframework.messaging.support.GenericMessage;
|
import org.springframework.messaging.support.GenericMessage;
|
||||||
|
import org.springframework.messaging.support.MessageBuilder;
|
||||||
|
import org.springframework.messaging.support.MessageHeaderAccessor;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
|
||||||
import static java.nio.charset.StandardCharsets.*;
|
import static java.nio.charset.StandardCharsets.*;
|
||||||
|
@ -89,6 +92,13 @@ public class MessageMappingMessageHandlerTests {
|
||||||
verifyOutputContent(Collections.singletonList("abcdef::response"));
|
verifyOutputContent(Collections.singletonList("abcdef::response"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void handleWithDestinationVariable() {
|
||||||
|
MessageMappingMessageHandler messsageHandler = initMesssageHandler();
|
||||||
|
messsageHandler.handleMessage(message("destination.test", "abcdef")).block(Duration.ofSeconds(5));
|
||||||
|
verifyOutputContent(Collections.singletonList("test::abcdef::response"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void handleException() {
|
public void handleException() {
|
||||||
MessageMappingMessageHandler messsageHandler = initMesssageHandler();
|
MessageMappingMessageHandler messsageHandler = initMesssageHandler();
|
||||||
|
@ -143,9 +153,11 @@ public class MessageMappingMessageHandlerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Message<?> message(String destination, String... content) {
|
private Message<?> message(String destination, String... content) {
|
||||||
return new GenericMessage<>(
|
Flux<DataBuffer> payload = Flux.fromIterable(Arrays.asList(content)).map(parts -> toDataBuffer(parts));
|
||||||
Flux.fromIterable(Arrays.asList(content)).map(payload -> toDataBuffer(payload)),
|
MessageHeaderAccessor headers = new MessageHeaderAccessor();
|
||||||
Collections.singletonMap(DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER, destination));
|
headers.setLeaveMutable(true);
|
||||||
|
headers.setHeader(DestinationPatternsMessageCondition.LOOKUP_DESTINATION_HEADER, destination);
|
||||||
|
return MessageBuilder.createMessage(payload, headers.getMessageHeaders());
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataBuffer toDataBuffer(String payload) {
|
private DataBuffer toDataBuffer(String payload) {
|
||||||
|
@ -181,6 +193,11 @@ public class MessageMappingMessageHandlerTests {
|
||||||
return payload + "::response";
|
return payload + "::response";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MessageMapping("destination.{variable}")
|
||||||
|
String handleWithDestinationVariable(@DestinationVariable String variable, String payload) {
|
||||||
|
return variable + "::" + payload + "::response";
|
||||||
|
}
|
||||||
|
|
||||||
@MessageMapping("exception")
|
@MessageMapping("exception")
|
||||||
String handleAndThrow() {
|
String handleAndThrow() {
|
||||||
throw new IllegalArgumentException("rejected");
|
throw new IllegalArgumentException("rejected");
|
||||||
|
|
Loading…
Reference in New Issue