This is an automated email from the ASF dual-hosted git repository. lukaszlenart pushed a commit to branch feature/WW-3576-session-map-staleness in repository https://gitbox.apache.org/repos/asf/struts.git
commit 499415ea2c467cb3922e821874a9dbff67594345 Author: Lukasz Lenart <[email protected]> AuthorDate: Sun Oct 18 08:59:09 2026 +0200 WW-3576 fix(core): keep the pinned session in a local in SessionMap.put and harden the race test Co-Authored-By: Claude Opus 5.5 <[email protected]> --- core/src/main/java/org/apache/struts2/dispatcher/SessionMap.java | 7 ++++--- .../test/java/org/apache/struts2/dispatcher/SessionMapTest.java | 7 +++++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/apache/struts2/dispatcher/SessionMap.java b/core/src/main/java/org/apache/struts2/dispatcher/SessionMap.java index 54318391b..07b1ddffd 100644 --- a/core/src/main/java/org/apache/struts2/dispatcher/SessionMap.java +++ b/core/src/main/java/org/apache/struts2/dispatcher/SessionMap.java @@ -157,10 +157,11 @@ public class SessionMap extends AbstractMap<String, Object> implements Serializa HttpSession current = session; if (current == null) { synchronized (this) { - if (session == null) { - session = request.getSession(true); - } current = session; + if (current == null) { + current = request.getSession(true); + session = current; + } } } diff --git a/core/src/test/java/org/apache/struts2/dispatcher/SessionMapTest.java b/core/src/test/java/org/apache/struts2/dispatcher/SessionMapTest.java index 3edc9c380..5a602ebad 100644 --- a/core/src/test/java/org/apache/struts2/dispatcher/SessionMapTest.java +++ b/core/src/test/java/org/apache/struts2/dispatcher/SessionMapTest.java @@ -296,12 +296,13 @@ public class SessionMapTest extends TestCase { request.setSession(session); SessionMap sessionMap = new SessionMap(request); AtomicReference<Throwable> failure = new AtomicReference<>(); + AtomicReference<Object> read = new AtomicReference<>(); Thread invalidator = new Thread(sessionMap::invalidate); invalidator.start(); invalidating.await(); Thread reader = new Thread(() -> { - try { sessionMap.get("key"); } catch (Throwable t) { failure.set(t); } + try { read.set(sessionMap.get("key")); } catch (Throwable t) { failure.set(t); } }); reader.start(); long deadline = System.currentTimeMillis() + 5000; @@ -313,7 +314,9 @@ public class SessionMapTest extends TestCase { invalidator.join(5000); reader.join(5000); - assertNull("get() concurrent with invalidate() threw", failure.get()); + assertFalse("reader did not finish", reader.isAlive()); + assertNull("get() concurrent with invalidate() threw: " + failure.get(), failure.get()); + assertEquals("value", read.get()); } @Override
