Skip to content

Commit e7ecb83

Browse files
committed
Add client responder configuration
Prior to this commit, the `RSocketRequester.Builder` would allow to configure directly annotated handlers for processing server requests. This lead to a package tangle where the `o.s.messaging.rsocket` would use classes from `o.s.messaging.rsocket.annotation.support` package. This commit introduces the `ClientResponderFactory` interface for configuring a responder on the client RSocket factory. Its goal is to be compatible with future changes with a functional variant for RSocket handlers. Closes gh-23170
1 parent d6e3394 commit e7ecb83

File tree

5 files changed

+224
-31
lines changed

5 files changed

+224
-31
lines changed

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

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818

1919
import java.net.URI;
2020
import java.util.ArrayList;
21-
import java.util.Arrays;
2221
import java.util.List;
2322
import java.util.function.Consumer;
2423
import java.util.stream.Stream;
@@ -31,7 +30,6 @@
3130
import reactor.core.publisher.Mono;
3231

3332
import org.springframework.lang.Nullable;
34-
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;
3533
import org.springframework.util.Assert;
3634
import org.springframework.util.MimeType;
3735

@@ -56,7 +54,6 @@ final class DefaultRSocketRequesterBuilder implements RSocketRequester.Builder {
5654

5755
private List<Consumer<RSocketStrategies.Builder>> strategiesConfigurers = new ArrayList<>();
5856

59-
private List<Object> handlers = new ArrayList<>();
6057

6158
@Override
6259
public RSocketRequester.Builder dataMimeType(@Nullable MimeType mimeType) {
@@ -83,12 +80,6 @@ public RSocketRequester.Builder rsocketStrategies(@Nullable RSocketStrategies st
8380
return this;
8481
}
8582

86-
@Override
87-
public RSocketRequester.Builder annotatedHandlers(Object... handlers) {
88-
this.handlers.addAll(Arrays.asList(handlers));
89-
return this;
90-
}
91-
9283
@Override
9384
public RSocketRequester.Builder rsocketStrategies(Consumer<RSocketStrategies.Builder> configurer) {
9485
this.strategiesConfigurers.add(configurer);
@@ -120,13 +111,6 @@ private Mono<RSocketRequester> doConnect(ClientTransport transport) {
120111
rsocketFactory.dataMimeType(dataMimeType.toString());
121112
rsocketFactory.metadataMimeType(this.metadataMimeType.toString());
122113

123-
if (!this.handlers.isEmpty()) {
124-
RSocketMessageHandler messageHandler = new RSocketMessageHandler();
125-
messageHandler.setHandlers(this.handlers);
126-
messageHandler.setRSocketStrategies(rsocketStrategies);
127-
messageHandler.afterPropertiesSet();
128-
rsocketFactory.acceptor(messageHandler.clientResponder());
129-
}
130114
rsocketFactory.frameDecoder(PayloadDecoder.ZERO_COPY);
131115
this.factoryConfigurers.forEach(consumer -> consumer.accept(rsocketFactory));
132116

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

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import org.springframework.core.ParameterizedTypeReference;
3131
import org.springframework.core.ReactiveAdapterRegistry;
3232
import org.springframework.lang.Nullable;
33-
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;
3433
import org.springframework.util.MimeType;
3534

3635
/**
@@ -65,7 +64,6 @@ public interface RSocketRequester {
6564
*/
6665
MimeType metadataMimeType();
6766

68-
6967
/**
7068
* Begin to specify a new request with the given route to a remote handler.
7169
* <p>If the connection is set to use composite metadata, the route is
@@ -158,6 +156,7 @@ interface Builder {
158156
/**
159157
* Set the {@link RSocketStrategies} to use for access to encoders,
160158
* decoders, and a factory for {@code DataBuffer's}.
159+
* @param strategies the codecs strategies to use
161160
*/
162161
RSocketRequester.Builder rsocketStrategies(@Nullable RSocketStrategies strategies);
163162

@@ -170,17 +169,6 @@ interface Builder {
170169
*/
171170
RSocketRequester.Builder rsocketStrategies(Consumer<RSocketStrategies.Builder> configurer);
172171

173-
/**
174-
* Add handlers for processing requests sent by the server.
175-
* <p>This is a shortcut for registering client handlers (i.e. annotated controllers)
176-
* to a {@link RSocketMessageHandler} and configuring it as an acceptor.
177-
* You can take full control by manually registering an acceptor on the
178-
* {@link io.rsocket.RSocketFactory.ClientRSocketFactory} using
179-
* {@link #rsocketFactory(Consumer)} instead.
180-
* @param handlers the client handlers to configure on the requester
181-
*/
182-
RSocketRequester.Builder annotatedHandlers(Object... handlers);
183-
184172
/**
185173
* Connect to the RSocket server over TCP.
186174
* @param host the server host
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright 2002-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.messaging.rsocket.annotation.support;
18+
19+
import java.util.function.Consumer;
20+
21+
import io.rsocket.RSocketFactory;
22+
23+
import org.springframework.messaging.handler.invocation.reactive.ArgumentResolverConfigurer;
24+
import org.springframework.messaging.handler.invocation.reactive.ReturnValueHandlerConfigurer;
25+
import org.springframework.messaging.rsocket.RSocketStrategies;
26+
import org.springframework.util.RouteMatcher;
27+
28+
/**
29+
* Build and configure a responder on a {@link RSocketFactory.ClientRSocketFactory} in order
30+
* to handle requests sent by the RSocket server to the client.
31+
* <p>This can be configured as a responder on a {@link org.springframework.messaging.rsocket.RSocketRequester}
32+
* being built by passing it as an argument to the
33+
* {@link org.springframework.messaging.rsocket.RSocketRequester.Builder#rsocketFactory} method.
34+
*
35+
* @author Brian Clozel
36+
* @since 5.2
37+
* @see org.springframework.messaging.rsocket.RSocketRequester
38+
*/
39+
public interface ClientResponderFactory extends Consumer<RSocketFactory.ClientRSocketFactory> {
40+
41+
/**
42+
* Create a new {@link ClientResponderFactory.Config} for handling requests with annotated handlers.
43+
*/
44+
static ClientResponderFactory.Config create() {
45+
return new DefaultClientResponderFactory();
46+
}
47+
48+
/**
49+
* Configure the client responder with infrastructure options
50+
* to be applied on the resulting {@link RSocketMessageHandler}.
51+
*/
52+
interface Config {
53+
54+
/**
55+
* Set the {@link RSocketStrategies} to use for access to encoders,
56+
* decoders, and a factory for {@code DataBuffer's}.
57+
* @param strategies the codecs strategies to use
58+
*/
59+
Config strategies(RSocketStrategies strategies);
60+
61+
/**
62+
* Set the {@link RouteMatcher} to use for matching incoming requests.
63+
* <p>If none is set, then the responder will use a default
64+
* {@link org.springframework.util.SimpleRouteMatcher} instance backed
65+
* by and {@link org.springframework.util.AntPathMatcher}.
66+
* @param routeMatcher the route matcher to use with the responder
67+
*/
68+
Config routeMatcher(RouteMatcher routeMatcher);
69+
70+
/**
71+
* Set the {@link MetadataExtractor} to use for extracting information
72+
* from metadata frames.
73+
* @param extractor the metadata extractor to use
74+
*/
75+
Config metadataExtractor(MetadataExtractor extractor);
76+
77+
/**
78+
* Set the {@link ReturnValueHandlerConfigurer} for configuring
79+
* return value handlers.
80+
* @param configurer the configurer to use
81+
*/
82+
Config returnValueHandler(ReturnValueHandlerConfigurer configurer);
83+
84+
/**
85+
* Set the {@link ArgumentResolverConfigurer} for configuring
86+
* argument resolvers.
87+
* @param configurer the configurer to use
88+
*/
89+
Config argumentResolver(ArgumentResolverConfigurer configurer);
90+
91+
/**
92+
* Set the annotated handlers in charge of processing the incoming RSocket requests.
93+
* @param handlers the annotated handlers
94+
*/
95+
ClientResponderFactory handlers(Object... handlers);
96+
97+
}
98+
99+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright 2002-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.messaging.rsocket.annotation.support;
18+
19+
import java.util.Arrays;
20+
import java.util.List;
21+
22+
import io.rsocket.RSocketFactory;
23+
24+
import org.springframework.lang.Nullable;
25+
import org.springframework.messaging.handler.invocation.reactive.ArgumentResolverConfigurer;
26+
import org.springframework.messaging.handler.invocation.reactive.ReturnValueHandlerConfigurer;
27+
import org.springframework.messaging.rsocket.RSocketStrategies;
28+
import org.springframework.util.Assert;
29+
import org.springframework.util.RouteMatcher;
30+
31+
/**
32+
* Default implementation of {@link ClientResponderFactory}.
33+
*
34+
* @author Brian Clozel
35+
*/
36+
class DefaultClientResponderFactory implements ClientResponderFactory, ClientResponderFactory.Config {
37+
38+
private List<Object> handlers;
39+
40+
@Nullable
41+
private RSocketStrategies strategies;
42+
43+
@Nullable
44+
private RouteMatcher routeMatcher;
45+
46+
@Nullable
47+
private MetadataExtractor extractor;
48+
49+
@Nullable
50+
private ReturnValueHandlerConfigurer returnValueHandlerConfigurer;
51+
52+
@Nullable
53+
private ArgumentResolverConfigurer argumentResolverConfigurer;
54+
55+
@Override
56+
public ClientResponderFactory handlers(Object... handlers) {
57+
Assert.notEmpty(handlers, "handlers should not be empty");
58+
this.handlers = Arrays.asList(handlers);
59+
return this;
60+
}
61+
62+
@Override
63+
public ClientResponderFactory.Config strategies(RSocketStrategies strategies) {
64+
this.strategies = strategies;
65+
return this;
66+
}
67+
68+
@Override
69+
public ClientResponderFactory.Config routeMatcher(RouteMatcher routeMatcher) {
70+
this.routeMatcher = routeMatcher;
71+
return this;
72+
}
73+
74+
@Override
75+
public ClientResponderFactory.Config metadataExtractor(MetadataExtractor extractor) {
76+
this.extractor = extractor;
77+
return this;
78+
}
79+
80+
@Override
81+
public ClientResponderFactory.Config returnValueHandler(ReturnValueHandlerConfigurer configurer) {
82+
this.returnValueHandlerConfigurer = configurer;
83+
return this;
84+
}
85+
86+
@Override
87+
public ClientResponderFactory.Config argumentResolver(ArgumentResolverConfigurer configurer) {
88+
this.argumentResolverConfigurer = configurer;
89+
return this;
90+
}
91+
92+
@Override
93+
public void accept(RSocketFactory.ClientRSocketFactory clientRSocketFactory) {
94+
Assert.notEmpty(this.handlers, "handlers should not be empty");
95+
RSocketMessageHandler messageHandler = new RSocketMessageHandler();
96+
messageHandler.setHandlers(this.handlers);
97+
if (this.strategies != null) {
98+
messageHandler.setRSocketStrategies(this.strategies);
99+
}
100+
if (this.routeMatcher != null) {
101+
messageHandler.setRouteMatcher(this.routeMatcher);
102+
}
103+
if (this.extractor != null) {
104+
messageHandler.setMetadataExtractor(this.extractor);
105+
}
106+
if (this.returnValueHandlerConfigurer != null) {
107+
messageHandler.setReturnValueHandlerConfigurer(this.returnValueHandlerConfigurer);
108+
}
109+
if (this.argumentResolverConfigurer != null) {
110+
messageHandler.setArgumentResolverConfigurer(this.argumentResolverConfigurer);
111+
}
112+
messageHandler.afterPropertiesSet();
113+
clientRSocketFactory.acceptor(messageHandler.clientResponder());
114+
}
115+
116+
}

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.springframework.core.io.buffer.NettyDataBufferFactory;
4343
import org.springframework.messaging.handler.annotation.MessageMapping;
4444
import org.springframework.messaging.rsocket.annotation.ConnectMapping;
45+
import org.springframework.messaging.rsocket.annotation.support.ClientResponderFactory;
4546
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;
4647
import org.springframework.stereotype.Controller;
4748

@@ -102,17 +103,22 @@ private static void connectAndRunTest(String connectionRoute) {
102103

103104
ServerController serverController = context.getBean(ServerController.class);
104105
serverController.reset();
106+
RSocketStrategies rSocketStrategies = context.getBean(RSocketStrategies.class);
107+
108+
ClientResponderFactory clientResponder = ClientResponderFactory.create()
109+
.strategies(rSocketStrategies)
110+
.handlers(new ClientHandler());
105111

106112
RSocketRequester requester = null;
107113
try {
108114
requester = RSocketRequester.builder()
109-
.annotatedHandlers(new ClientHandler())
110115
.rsocketFactory(factory -> {
111116
factory.metadataMimeType("text/plain");
112117
factory.setupPayload(ByteBufPayload.create("", connectionRoute));
113118
factory.frameDecoder(PayloadDecoder.ZERO_COPY);
114119
})
115-
.rsocketStrategies(context.getBean(RSocketStrategies.class))
120+
.rsocketFactory(clientResponder)
121+
.rsocketStrategies(rSocketStrategies)
116122
.connectTcp("localhost", server.address().getPort())
117123
.block();
118124

0 commit comments

Comments
 (0)