Skip to content

Commit 222702f

Browse files
committed
Polish WebSession support and tests
1 parent 7bb19fc commit 222702f

File tree

5 files changed

+48
-44
lines changed

5 files changed

+48
-44
lines changed

spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 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.
@@ -107,12 +107,12 @@ default <T> T getAttributeOrDefault(String name, T defaultValue) {
107107
}
108108

109109
/**
110-
* Return the web session for the current request. Always guaranteed to
111-
* return an instance either matching to the session id requested by the
112-
* client, or with a new session id either because the client did not
113-
* specify one or because the underlying session had expired. Use of this
114-
* method does not automatically create a session. See {@link WebSession}
115-
* for more details.
110+
* Return the web session for the current request.
111+
* <p>Always guaranteed to return either an instance matching the session id
112+
* requested by the client, or a new session either because the client did not
113+
* specify a session id or because the underlying session expired.
114+
* <p>Use of this method does not automatically create a session. See
115+
* {@link WebSession} for more details.
116116
*/
117117
Mono<WebSession> getSession();
118118

spring-web/src/main/java/org/springframework/web/server/session/InMemoryWebSessionStore.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ public int getMaxSessions() {
7979
}
8080

8181
/**
82-
* Configure the {@link Clock} to use to set lastAccessTime on every created
83-
* session and to calculate if it is expired.
84-
* <p>This may be useful to align to different timezone or to set the clock
82+
* Configure the {@link Clock} to use to set the {@code lastAccessTime} on
83+
* every created session and to calculate if the session has expired.
84+
* <p>This may be useful to align to different time zones or to set the clock
8585
* back in a test, for example, {@code Clock.offset(clock, Duration.ofMinutes(-31))}
8686
* in order to simulate session expiration.
8787
* <p>By default this is {@code Clock.system(ZoneId.of("GMT"))}.
@@ -94,16 +94,17 @@ public void setClock(Clock clock) {
9494
}
9595

9696
/**
97-
* Return the configured clock for session lastAccessTime calculations.
97+
* Return the configured clock for session {@code lastAccessTime} calculations.
9898
*/
9999
public Clock getClock() {
100100
return this.clock;
101101
}
102102

103103
/**
104-
* Return the map of sessions with an {@link Collections#unmodifiableMap
105-
* unmodifiable} wrapper. This could be used for management purposes, to
106-
* list active sessions, invalidate expired ones, etc.
104+
* Return an {@linkplain Collections#unmodifiableMap unmodifiable} copy of the
105+
* map of sessions.
106+
* <p>This could be used for management purposes, to list active sessions,
107+
* to invalidate expired sessions, etc.
107108
* @since 5.0.8
108109
*/
109110
public Map<String, WebSession> getSessions() {
@@ -157,10 +158,11 @@ public Mono<WebSession> updateLastAccessTime(WebSession session) {
157158
}
158159

159160
/**
160-
* Check for expired sessions and remove them. Typically such checks are
161-
* kicked off lazily during calls to {@link #createWebSession() create} or
162-
* {@link #retrieveSession retrieve}, no less than 60 seconds apart.
163-
* This method can be called to force a check at a specific time.
161+
* Check for expired sessions and remove them.
162+
* <p>Typically such checks are kicked off lazily during calls to
163+
* {@link #createWebSession()} or {@link #retrieveSession}, no less than 60
164+
* seconds apart.
165+
* <p>This method can be called to force a check at a specific time.
164166
* @since 5.0.8
165167
*/
166168
public void removeExpiredSessions() {

spring-web/src/main/java/org/springframework/web/server/session/WebSessionManager.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@
3232
public interface WebSessionManager {
3333

3434
/**
35-
* Return the {@link WebSession} for the given exchange. Always guaranteed
36-
* to return an instance either matching to the session id requested by the
37-
* client, or a new session either because the client did not specify one
38-
* or because the underlying session expired.
35+
* Return the {@link WebSession} for the given exchange.
36+
* <p>Always guaranteed to return either an instance matching the session id
37+
* requested by the client, or a new session either because the client did not
38+
* specify a session id or because the underlying session expired.
3939
* @param exchange the current exchange
4040
* @return promise for the WebSession
4141
*/

spring-web/src/main/java/org/springframework/web/server/session/WebSessionStore.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 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.
@@ -43,7 +43,7 @@ public interface WebSessionStore {
4343
* Return the WebSession for the given id.
4444
* <p><strong>Note:</strong> This method should perform an expiration check,
4545
* and if it has expired remove the session and return empty. This method
46-
* should also update the lastAccessTime of retrieved sessions.
46+
* should also update the {@code lastAccessTime} of retrieved sessions.
4747
* @param sessionId the session to load
4848
* @return the session, or an empty {@code Mono}
4949
*/

spring-web/src/test/java/org/springframework/web/server/session/InMemoryWebSessionStoreTests.java

Lines changed: 22 additions & 20 deletions
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.
@@ -19,7 +19,6 @@
1919
import java.time.Clock;
2020
import java.time.Duration;
2121
import java.time.Instant;
22-
import java.util.Map;
2322
import java.util.stream.IntStream;
2423

2524
import org.junit.jupiter.api.Test;
@@ -35,10 +34,11 @@
3534
* Tests for {@link InMemoryWebSessionStore}.
3635
*
3736
* @author Rob Winch
37+
* @author Sam Brannen
3838
*/
3939
class InMemoryWebSessionStoreTests {
4040

41-
private InMemoryWebSessionStore store = new InMemoryWebSessionStore();
41+
private final InMemoryWebSessionStore store = new InMemoryWebSessionStore();
4242

4343

4444
@Test
@@ -59,7 +59,7 @@ void startsSessionImplicitly() {
5959
}
6060

6161
@Test // gh-24027, gh-26958
62-
public void createSessionDoesNotBlock() {
62+
void createSessionDoesNotBlock() {
6363
this.store.createWebSession()
6464
.doOnNext(session -> assertThat(Schedulers.isInNonBlockingThread()).isTrue())
6565
.block();
@@ -103,7 +103,7 @@ void lastAccessTimeIsUpdatedOnRetrieve() {
103103
}
104104

105105
@Test // SPR-17051
106-
public void sessionInvalidatedBeforeSave() {
106+
void sessionInvalidatedBeforeSave() {
107107
// Request 1 creates session
108108
WebSession session1 = this.store.createWebSession().block();
109109
assertThat(session1).isNotNull();
@@ -132,33 +132,31 @@ public void sessionInvalidatedBeforeSave() {
132132

133133
@Test
134134
void expirationCheckPeriod() {
135-
136-
DirectFieldAccessor accessor = new DirectFieldAccessor(this.store);
137-
Map<?,?> sessions = (Map<?, ?>) accessor.getPropertyValue("sessions");
138-
assertThat(sessions).isNotNull();
139-
140135
// Create 100 sessions
141-
IntStream.range(0, 100).forEach(i -> insertSession());
142-
assertThat(sessions).hasSize(100);
136+
IntStream.rangeClosed(1, 100).forEach(i -> insertSession());
137+
assertNumSessions(100);
143138

144-
// Force a new clock (31 min later), don't use setter which would clean expired sessions
139+
// Force a new clock (31 min later). Don't use setter which would clean expired sessions.
140+
DirectFieldAccessor accessor = new DirectFieldAccessor(this.store);
145141
accessor.setPropertyValue("clock", Clock.offset(this.store.getClock(), Duration.ofMinutes(31)));
146-
assertThat(sessions).hasSize(100);
142+
assertNumSessions(100);
147143

148-
// Create 1 more which forces a time-based check (clock moved forward)
144+
// Create 1 more which forces a time-based check (clock moved forward).
149145
insertSession();
150-
assertThat(sessions).hasSize(1);
146+
assertNumSessions(1);
151147
}
152148

153149
@Test
154150
void maxSessions() {
151+
this.store.setMaxSessions(10);
155152

156-
IntStream.range(0, 10000).forEach(i -> insertSession());
157-
assertThatIllegalStateException().isThrownBy(
158-
this::insertSession)
159-
.withMessage("Max sessions limit reached: 10000");
153+
IntStream.rangeClosed(1, 10).forEach(i -> insertSession());
154+
assertThatIllegalStateException()
155+
.isThrownBy(this::insertSession)
156+
.withMessage("Max sessions limit reached: 10");
160157
}
161158

159+
162160
private WebSession insertSession() {
163161
WebSession session = this.store.createWebSession().block();
164162
assertThat(session).isNotNull();
@@ -167,4 +165,8 @@ private WebSession insertSession() {
167165
return session;
168166
}
169167

168+
private void assertNumSessions(int numSessions) {
169+
assertThat(store.getSessions()).hasSize(numSessions);
170+
}
171+
170172
}

0 commit comments

Comments
 (0)