Skip to content

Commit ecdb633

Browse files
committed
Merge branch '6.2.x'
2 parents f8e7bf7 + c067919 commit ecdb633

File tree

3 files changed

+101
-50
lines changed

3 files changed

+101
-50
lines changed

spring-webflux/src/main/java/org/springframework/web/reactive/result/view/Fragment.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -86,9 +86,7 @@ public void mergeAttributes(Model model) {
8686
if (CollectionUtils.isEmpty(model.asMap())) {
8787
return;
8888
}
89-
if (this.model == null) {
90-
this.model = new LinkedHashMap<>();
91-
}
89+
this.model = new LinkedHashMap<>(this.model != null ? this.model : Collections.emptyMap());
9290
model.asMap().forEach((key, value) -> this.model.putIfAbsent(key, value));
9391
}
9492

spring-webflux/src/main/java/org/springframework/web/reactive/socket/WebSocketHandler.java

+50-46
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -23,65 +23,69 @@
2323
import reactor.core.publisher.Mono;
2424

2525
/**
26-
* Handler for a WebSocket session.
27-
*
28-
* <p>A server {@code WebSocketHandler} is mapped to requests with
26+
* Handler for a WebSocket messages. You can use it as follows:
27+
* <ul>
28+
* <li>On the server side, {@code WebSocketHandler} is mapped to requests with
2929
* {@link org.springframework.web.reactive.handler.SimpleUrlHandlerMapping
3030
* SimpleUrlHandlerMapping} and
3131
* {@link org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter
32-
* WebSocketHandlerAdapter}. A client {@code WebSocketHandler} is passed to the
32+
* WebSocketHandlerAdapter}.
33+
* <li>On the client side, {@code WebSocketHandler} is passed into the
3334
* {@link org.springframework.web.reactive.socket.client.WebSocketClient
3435
* WebSocketClient} execute method.
36+
* </ul>
3537
*
36-
* <p>Use {@link WebSocketSession#receive() session.receive()} to compose on
37-
* the inbound message stream, and {@link WebSocketSession#send(Publisher)
38-
* session.send(publisher)} for the outbound message stream. Below is an
39-
* example, combined flow to process inbound and to send outbound messages:
38+
* <p>{@link WebSocketSession#receive() session.receive()} handles inbound
39+
* messages, while {@link WebSocketSession#send(Publisher) session.send}
40+
* sends outbound messages. Below is an example of handling inbound messages
41+
* and responding to every message:
4042
*
4143
* <pre class="code">
42-
* class ExampleHandler implements WebSocketHandler {
43-
*
44-
* &#064;Override
45-
* public Mono&lt;Void&gt; handle(WebSocketSession session) {
46-
*
47-
* Flux&lt;WebSocketMessage&gt; output = session.receive()
48-
* .doOnNext(message -&gt; {
49-
* // ...
50-
* })
51-
* .concatMap(message -&gt; {
52-
* // ...
53-
* })
54-
* .map(value -&gt; session.textMessage("Echo " + value));
55-
*
56-
* return session.send(output);
57-
* }
58-
* }
44+
* class ExampleHandler implements WebSocketHandler {
45+
*
46+
* &#064;Override
47+
* public Mono&lt;Void&gt; handle(WebSocketSession session) {
48+
* Flux&lt;WebSocketMessage&gt; output = session.receive()
49+
* .doOnNext(message -&gt; {
50+
* // Imperative calls without a return value:
51+
* // perform access checks, log, validate, update metrics.
52+
* // ...
53+
* })
54+
* .concatMap(message -&gt; {
55+
* // Async, non-blocking calls:
56+
* // parse messages, call a database, make remote calls.
57+
* // Return the same message, or a transformed value
58+
* // ...
59+
* });
60+
* return session.send(output);
61+
* }
62+
* }
5963
* </pre>
6064
*
6165
* <p>If processing inbound and sending outbound messages are independent
6266
* streams, they can be joined together with the "zip" operator:
6367
*
6468
* <pre class="code">
65-
* class ExampleHandler implements WebSocketHandler {
66-
*
67-
* &#064;Override
68-
* public Mono&lt;Void&gt; handle(WebSocketSession session) {
69-
*
70-
* Mono&lt;Void&gt; input = session.receive()
71-
* .doOnNext(message -&gt; {
72-
* // ...
73-
* })
74-
* .concatMap(message -&gt; {
75-
* // ...
76-
* })
77-
* .then();
78-
*
79-
* Flux&lt;String&gt; source = ... ;
80-
* Mono&lt;Void&gt; output = session.send(source.map(session::textMessage));
81-
*
82-
* return Mono.zip(input, output).then();
83-
* }
84-
* }
69+
* class ExampleHandler implements WebSocketHandler {
70+
*
71+
* &#064;Override
72+
* public Mono&lt;Void&gt; handle(WebSocketSession session) {
73+
*
74+
* Mono&lt;Void&gt; input = session.receive()
75+
* .doOnNext(message -&gt; {
76+
* // ...
77+
* })
78+
* .concatMap(message -&gt; {
79+
* // ...
80+
* })
81+
* .then();
82+
*
83+
* Flux&lt;String&gt; source = ... ;
84+
* Mono&lt;Void&gt; output = session.send(source.map(session::textMessage));
85+
*
86+
* return Mono.zip(input, output).then();
87+
* }
88+
* }
8589
* </pre>
8690
*
8791
* <p>A {@code WebSocketHandler} must compose the inbound and outbound streams
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2002-2025 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.web.reactive.result.view;
18+
19+
import java.util.Map;
20+
21+
import org.junit.jupiter.api.Test;
22+
23+
import org.springframework.ui.ConcurrentModel;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
/**
28+
* Unit tests for {@link Fragment}.
29+
* @author Rossen Stoyanchev
30+
*/
31+
public class FragmentTests {
32+
33+
@Test
34+
void mergeAttributes() {
35+
Fragment fragment = Fragment.create("myView", Map.of("fruit", "apple"));
36+
fragment.mergeAttributes(new ConcurrentModel("vegetable", "pepper"));
37+
38+
assertThat(fragment.model()).containsExactly(Map.entry("fruit", "apple"), Map.entry("vegetable", "pepper"));
39+
}
40+
41+
@Test
42+
void mergeAttributesCollision() {
43+
Fragment fragment = Fragment.create("myView", Map.of("fruit", "apple"));
44+
fragment.mergeAttributes(new ConcurrentModel("fruit", "orange"));
45+
46+
assertThat(fragment.model()).containsExactly(Map.entry("fruit", "apple"));
47+
}
48+
49+
}

0 commit comments

Comments
 (0)