Fix for ChainedWorkspaceReader#1909
Conversation
The readers are immutable, and repository is derived from (immutable) readers, hence, repository is immutable as well.
gnodet
left a comment
There was a problem hiding this comment.
Hi @cstamas, thanks for the clean-up! The reasoning is sound — since WorkspaceRepository is immutable and Key captures repository keys at construction time, the lazy-recreation logic in getRepository() is indeed redundant given that the readers list is now fixed at construction time.
A few minor points worth discussing before merging:
-
Null-handling behaviour change (see inline): passing a literal
nullvarargs now throwsNPEimmediately (previously it was silently treated as an empty list), while individualnullelements in the array are now silently dropped (previously they were included and would NPE later). Neither case is part of the documented contract, but it’s a subtle behaviour change that could surprise callers. -
Undocumented assumption about reader stability (see inline): the correctness of the new code rests on the assumption that
WorkspaceReaderimplementations return a stableWorkspaceRepository(same key) for their entire lifetime.WorkspaceRepositoryis immutable, which makes this very likely in practice, butWorkspaceReaderis an interface. A brief comment capturing this assumption would make the code easier to reason about for future contributors. -
Minor style (see inline):
Collectors.toCollection(ArrayList::new)can be simplified. -
Tests: there are no unit tests for
ChainedWorkspaceReader. A basic test covering construction,findArtifact,findVersions, andgetRepositorywould be a nice addition — especially one that verifies the null-filtering behaviour now that it is an explicit choice.
The @Override additions are good hygiene — thanks for those.
Overall this is a reasonable simplification; just wanted to flag the subtle behaviour differences. Happy to see it land once the above is addressed (or consciously accepted).
— Guillaume (gnodet)
| } | ||
|
|
||
| ArrayList<WorkspaceReader> list = | ||
| Arrays.stream(readers).filter(Objects::nonNull).collect(Collectors.toCollection(ArrayList::new)); |
There was a problem hiding this comment.
Nit: note that this slightly changes the null-handling behaviour compared to the previous code. The old Collections.addAll(this.readers, readers) would silently accept a null varargs array (treating it as empty), whereas Arrays.stream(readers) will throw NullPointerException if readers itself is null. On the other hand, individual null elements in the array were previously included (causing an NPE later when iterating), while now they are filtered out. Worth documenting these behaviour changes in Javadoc or a comment, even if null inputs aren’t part of the intended public contract.
| if (!key.equals(repository.getKey())) { | ||
| repository = new WorkspaceRepository(repository.getContentType(), key); | ||
| } | ||
| return repository; |
There was a problem hiding this comment.
The simplification here hinges on the assumption that WorkspaceReader.getRepository() always returns a repository whose getKey() is stable for the lifetime of the reader. WorkspaceRepository itself is indeed immutable (its key field is final), but WorkspaceReader is an interface — an implementation could theoretically return a different WorkspaceRepository instance with a different key on each invocation. The old code defended against that case by re-checking the key on every call. Would be good to document this assumption, e.g. with a comment like // Assumes WorkspaceReader.getRepository() returns a stable (immutable) repository for the reader’s lifetime.
| ArrayList<WorkspaceReader> list = | ||
| Arrays.stream(readers).filter(Objects::nonNull).collect(Collectors.toCollection(ArrayList::new)); |
There was a problem hiding this comment.
Minor style point: since the collected list is immediately wrapped in Collections.unmodifiableList, the exact ArrayList implementation doesn’t matter. You could simplify to .collect(Collectors.toList()), or, since maven-resolver targets Java 11+, even use Stream.of(readers).filter(Objects::nonNull).collect(Collectors.toUnmodifiableList()) (Java 10+).
|
@gnodet Windows failed with See https://github.com/apache/maven-resolver/actions/runs/27139141318/job/80106163823?pr=1909 |
|
The Root cause: When the loser thread's lock acquisition times out in A secondary issue: |
The readers are immutable, and repository is derived from (immutable) readers, hence, repository is immutable as well.
This PR does not modify API nor behaviour of this class, but removes redundant change detection of immutable readers list.