Skip to content

Commit ed65089

Browse files
committed
Add filter to add exchange to Reactor Context
Closes gh-21746
1 parent c99d904 commit ed65089

File tree

2 files changed

+135
-0
lines changed

2 files changed

+135
-0
lines changed
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
package org.springframework.web.filter.reactive;
17+
18+
import java.util.Optional;
19+
20+
import reactor.core.publisher.Mono;
21+
import reactor.util.context.Context;
22+
23+
import org.springframework.web.server.ServerWebExchange;
24+
import org.springframework.web.server.WebFilter;
25+
import org.springframework.web.server.WebFilterChain;
26+
27+
/**
28+
* Inserts an attribute in the Reactor {@link Context} that makes the current
29+
* {@link ServerWebExchange} available under the attribute name
30+
* {@link #EXCHANGE_CONTEXT_ATTRIBUTE}. This is useful for access to the
31+
* exchange without explicitly passing it to components that participate in
32+
* request processing.
33+
*
34+
* <p>The convenience method {@link #get(Context)} looks up the exchange.
35+
*
36+
* @author Rossen Stoyanchev
37+
* @since 5.2
38+
*/
39+
public class ServerWebExchangeContextFilter implements WebFilter {
40+
41+
/** Attribute name under which the exchange is saved in the context. */
42+
public static final String EXCHANGE_CONTEXT_ATTRIBUTE =
43+
ServerWebExchangeContextFilter.class.getName() + ".EXCHANGE_CONTEXT";
44+
45+
46+
@Override
47+
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
48+
return chain.filter(exchange)
49+
.subscriberContext(cxt -> cxt.put(EXCHANGE_CONTEXT_ATTRIBUTE, exchange));
50+
}
51+
52+
53+
/**
54+
* Access the {@link ServerWebExchange} from the Reactor Context, if available,
55+
* which is if {@link ServerWebExchangeContextFilter} is configured for use
56+
* and the give context was obtained from a request processing chain.
57+
* @param context the context in which to access the exchange
58+
* @return the exchange
59+
*/
60+
public static Optional<ServerWebExchange> get(Context context) {
61+
return context.getOrEmpty(EXCHANGE_CONTEXT_ATTRIBUTE);
62+
}
63+
64+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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+
package org.springframework.web.filter.reactive;
17+
18+
import java.time.Duration;
19+
import java.util.concurrent.atomic.AtomicReference;
20+
21+
import org.junit.Test;
22+
import reactor.core.publisher.Mono;
23+
24+
import org.springframework.http.server.reactive.HttpHandler;
25+
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
26+
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
27+
import org.springframework.web.server.ServerWebExchange;
28+
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
29+
30+
import static org.junit.Assert.*;
31+
32+
/**
33+
* Unit tests for {@link ServerWebExchangeContextFilter}.
34+
* @author Rossen Stoyanchev
35+
*/
36+
public class ServerWebExchangeContextFilterTests {
37+
38+
@Test
39+
public void extractServerWebExchangeFromContext() {
40+
MyService service = new MyService();
41+
42+
HttpHandler httpHandler = WebHttpHandlerBuilder
43+
.webHandler(exchange -> service.service().then())
44+
.filter(new ServerWebExchangeContextFilter())
45+
.build();
46+
47+
httpHandler.handle(MockServerHttpRequest.get("/path").build(), new MockServerHttpResponse())
48+
.block(Duration.ofSeconds(5));
49+
50+
assertNotNull(service.getExchange());
51+
}
52+
53+
54+
private static class MyService {
55+
56+
private final AtomicReference<ServerWebExchange> exchangeRef = new AtomicReference<>();
57+
58+
59+
public ServerWebExchange getExchange() {
60+
return this.exchangeRef.get();
61+
}
62+
63+
public Mono<String> service() {
64+
return Mono.just("result").subscriberContext(context -> {
65+
ServerWebExchangeContextFilter.get(context).ifPresent(exchangeRef::set);
66+
return context;
67+
});
68+
}
69+
}
70+
71+
}

0 commit comments

Comments
 (0)