From 2243fea873c3db99a25127120020daa40b934231 Mon Sep 17 00:00:00 2001 From: arendomoda Date: Fri, 7 Aug 2026 14:46:38 +0200 Subject: [PATCH 1/2] GH-1789 - Use ConcurrentHashMap for the module dependency cache. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #1789 `TestExecutionCondition.evaluate(…)` is called concurrently when `junit.jupiter.execution.parallel.mode.classes.default=concurrent` is configured, so `computeIfAbsent` on the plain `HashMap` can fail with a `ConcurrentModificationException`. Switching to `ConcurrentHashMap` keeps the caching behaviour and makes the field safe for concurrent access; `ApplicationModule.getAllDependencies(…)` never returns `null`, so the map's null-hostility is not a concern. Observed on 2.0.6 with 74 of 602 test classes failing per run (different classes each time). No regression test added: reproducing the race deterministically isn't practical. Happy to add a stress test if you'd prefer one. Signed-off-by: arendomoda --- .../modulith/junit/TestExecutionCondition.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/TestExecutionCondition.java b/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/TestExecutionCondition.java index 48a3d0087..0be2ed944 100644 --- a/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/TestExecutionCondition.java +++ b/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/TestExecutionCondition.java @@ -15,7 +15,7 @@ */ package org.springframework.modulith.junit; -import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.Map; import java.util.function.Function; @@ -45,7 +45,7 @@ class TestExecutionCondition { private static final Logger log = LoggerFactory.getLogger(TestExecutionCondition.class); private static final AnnotatedClassFinder SPA_CLASS_FINDER = new AnnotatedClassFinder(SpringBootConfiguration.class); - private final Map dependencies = new HashMap<>(); + private final Map dependencies = new ConcurrentHashMap<>(); ConditionEvaluationResult evaluate(ConditionContext context) { From d6bd1e04b720bbe5f7fc8c9857a951ae0b4c2f3c Mon Sep 17 00:00:00 2001 From: arendomoda Date: Fri, 7 Aug 2026 14:59:11 +0200 Subject: [PATCH 2/2] GH-1789 - Fix import order Signed-off-by: arendomoda --- .../springframework/modulith/junit/TestExecutionCondition.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/TestExecutionCondition.java b/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/TestExecutionCondition.java index 0be2ed944..e5b137aac 100644 --- a/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/TestExecutionCondition.java +++ b/spring-modulith-junit/src/main/java/org/springframework/modulith/junit/TestExecutionCondition.java @@ -15,8 +15,8 @@ */ package org.springframework.modulith.junit; -import java.util.concurrent.ConcurrentHashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import org.jspecify.annotations.Nullable;