Skip to content

Commit 56c2987

Browse files
committed
RSocketRequester support for route vars
Closes gh-23310
1 parent 358a6d6 commit 56c2987

File tree

3 files changed

+41
-8
lines changed

3 files changed

+41
-8
lines changed

spring-messaging/src/main/java/org/springframework/messaging/rsocket/DefaultRSocketRequester.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.util.Collections;
2020
import java.util.LinkedHashMap;
2121
import java.util.Map;
22+
import java.util.regex.Matcher;
23+
import java.util.regex.Pattern;
2224

2325
import io.netty.buffer.ByteBuf;
2426
import io.netty.buffer.ByteBufAllocator;
@@ -44,6 +46,7 @@
4446
import org.springframework.lang.Nullable;
4547
import org.springframework.util.Assert;
4648
import org.springframework.util.MimeType;
49+
import org.springframework.util.ObjectUtils;
4750

4851
/**
4952
* Default, package-private {@link RSocketRequester} implementation.
@@ -58,6 +61,9 @@ final class DefaultRSocketRequester implements RSocketRequester {
5861
static final MimeType ROUTING = new MimeType("message", "x.rsocket.routing.v0");
5962

6063

64+
/** For route variable replacement. */
65+
private static final Pattern VARS_PATTERN = Pattern.compile("\\{([^/]+?)\\}");
66+
6167
private static final Map<String, Object> EMPTY_HINTS = Collections.emptyMap();
6268

6369

@@ -105,11 +111,29 @@ public MimeType metadataMimeType() {
105111
}
106112

107113
@Override
108-
public RequestSpec route(String route) {
114+
public RequestSpec route(String route, Object... vars) {
109115
Assert.notNull(route, "'route' is required");
116+
route = expand(route, vars);
110117
return new DefaultRequestSpec(route, metadataMimeType().equals(COMPOSITE_METADATA) ? ROUTING : null);
111118
}
112119

120+
private static String expand(String route, Object... vars) {
121+
if (ObjectUtils.isEmpty(vars)) {
122+
return route;
123+
}
124+
StringBuffer sb = new StringBuffer();
125+
int index = 0;
126+
Matcher matcher = VARS_PATTERN.matcher(route);
127+
while (matcher.find()) {
128+
Assert.isTrue(index < vars.length, () -> "No value for variable '" + matcher.group(1) + "'");
129+
String value = vars[index].toString();
130+
value = value.contains(".") ? value.replaceAll("\\.", "%2E") : value;
131+
matcher.appendReplacement(sb, value);
132+
index++;
133+
}
134+
return sb.toString();
135+
}
136+
113137
@Override
114138
public RequestSpec metadata(Object metadata, @Nullable MimeType mimeType) {
115139
return new DefaultRequestSpec(metadata, mimeType);

spring-messaging/src/main/java/org/springframework/messaging/rsocket/RSocketRequester.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,19 @@ public interface RSocketRequester {
6666

6767
/**
6868
* Begin to specify a new request with the given route to a remote handler.
69+
* <p>The route can be a template with placeholders, e.g.
70+
* {@code "flight.{code}"} in which case the supplied route variables are
71+
* expanded into the template after being formatted via {@code toString()}.
72+
* If a formatted variable contains a "." it is replaced with the escape
73+
* sequence "%2E" to avoid treating it as separator by the responder .
6974
* <p>If the connection is set to use composite metadata, the route is
7075
* encoded as {@code "message/x.rsocket.routing.v0"}. Otherwise the route
7176
* is encoded according to the mime type for the connection.
7277
* @param route the route to a handler
78+
* @param routeVars variables to be expanded into the route template
7379
* @return a spec for further defining and executing the request
7480
*/
75-
RequestSpec route(String route);
81+
RequestSpec route(String route, Object... routeVars);
7682

7783
/**
7884
* Begin to specify a new request with the given metadata.

spring-messaging/src/test/java/org/springframework/messaging/rsocket/DefaultRSocketRequesterTests.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,16 @@ public void metadataMimeTypeMismatch() {
211211
}
212212

213213
@Test
214-
public void supportedMetadataMimeTypes() {
215-
216-
RSocketRequester.wrap(this.rsocket, TEXT_PLAIN,
217-
COMPOSITE_METADATA, this.strategies);
214+
public void routeWithVars() {
215+
RSocketRequester requester = RSocketRequester.wrap(this.rsocket, TEXT_PLAIN, TEXT_PLAIN, this.strategies);
216+
requester.route("a.{b}.{c}", "BBB", "C.C.C").data("body").send().block();
217+
assertThat(this.rsocket.getSavedPayload().getMetadataUtf8()).isEqualTo("a.BBB.C%2EC%2EC");
218+
}
218219

219-
RSocketRequester.wrap(this.rsocket, TEXT_PLAIN,
220-
ROUTING, this.strategies);
220+
@Test
221+
public void supportedMetadataMimeTypes() {
222+
RSocketRequester.wrap(this.rsocket, TEXT_PLAIN, COMPOSITE_METADATA, this.strategies);
223+
RSocketRequester.wrap(this.rsocket, TEXT_PLAIN, ROUTING, this.strategies);
221224
}
222225

223226
@Test

0 commit comments

Comments
 (0)