fix(maven): guard missing project index before auto-unbox - #12832
Conversation
Fix verified RED->GREEN. MojoExecutor auto-unbox NPE on missing project index at MojoExecutor.java:441
gnodet
left a comment
There was a problem hiding this comment.
Nice fix — clean, minimal, and correct.
What this does well:
- Replaces an opaque auto-unbox
NullPointerExceptionwith a descriptiveLifecycleExecutionException - Guards both the
indicesandprojectslookups (they're populated together inProjectIndexconstructor, but can diverge under concurrentHashMapmutation in parallel builds) - The
Integer idx→int index = idxpattern makes the null-safety guarantee local and compiler-enforced — good - Scope is appropriately narrow — doesn't try to fix the underlying
HashMapthread-safety inProjectIndex, which would be a separate, larger change
Minor suggestion (non-blocking): The error messages could mention the likely causes, to help users self-diagnose:
"No project index found for project " + projectId
+ ". This can happen with parallel builds (-T) or when extensions modify the session projects."Without the hint, users will just see "No project index found" and file another issue asking why. But this is a nice-to-have, not a blocker.
CI: Pending at time of review — please verify green before merge.
|
Thanks for the fix — the null guards are a clear improvement over the opaque NPE. One thing worth addressing in this PR though: Root cause:
|
gnodet
left a comment
There was a problem hiding this comment.
I think it would be better to fix the main cause at the same time.
…E guard Switch ProjectIndex's backing maps to ConcurrentHashMap to fix the root cause of index/project divergence under parallel builds (-T), and hint at the likely cause (parallel builds, extensions modifying session projects) in the guard exceptions added by this PR.
|
Done, switched ProjectIndex to ConcurrentHashMap and added the parallel-build/extension hint to the error messages in f892d1c. |
gnodet
left a comment
There was a problem hiding this comment.
Updated review after the second commit (f892d1c):
The ConcurrentHashMap change in ProjectIndex is the key addition — it fixes the root cause for parallel builds (-T), where the previous HashMap could silently corrupt under concurrent read/write, making .get() return null for keys that are present. With this change, the build actually succeeds in that scenario instead of just failing with a better message.
Note: the indices null guard (first commit) already overlaps with #12911 which was merged earlier today. The remaining value of this PR is:
ConcurrentHashMapinProjectIndex— the root cause fix (not in #12911)forkedProjectnull guard — defense-in-depth (not in #12911)- Enriched error messages — mention parallel builds / extensions as causes
CI is running on the latest push — once green, this looks good to merge.
# Conflicts: # impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
The enriched messages dropped the phrase MojoExecutorForkedExecutionTest asserts on, breaking maven-core after apache#12911 landed on master. Restore the original wording and keep the parallel-build/extension context appended.
|
Thanks for the review and the approval, @gnodet — and good catch on the #12911 overlap. CI was red on Verified locally on maven-core: 620 tests, 0 failures (was 1), Checkstyle 0 violations, Spotless clean. (The CI run for 9057215 is sitting in |
Fixes auto-unbox NPE in MojoExecutor when forked execution references a missing project.
Bug:
projectIndex.getIndices().get(projectId)returns null for an unknown projectId, thenint index = ...auto-unboxes null to NPE at MojoExecutor.java:441. SimilarlygetProjects().get(projectId)can return null, leading to NPE onclone.Root cause: In parallel builds (-T), the
projectsmap inProjectIndexis read and written concurrently through the same cached instance. PlainHashMapis not thread-safe for concurrent read/write, so it can appear to be missing a key that is actually present. Extensions that modify session projects can also cause a lookup to fail legitimately.Fix:
projectsmap inProjectIndexfromHashMaptoConcurrentHashMapso concurrent access in parallel builds no longer corrupts it.MojoExecutor.executeForkedExecutions()before the auto-unbox, throwing aLifecycleExecutionExceptionwith a message noting parallel builds and extensions modifying session projects as likely causes.Evidence: Verified with
mvn -pl impl/maven-core -am compile -Dspotless.check.skip=true -o, which returns BUILD SUCCESS. Branch verified against upstream/master.