gnodet-bot commented on code in PR #281:
URL: https://github.com/apache/maven/pull/281#discussion_r3987063591
##########
impl/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java:
##########
@@ -65,6 +67,46 @@
*/
public class RepositoryUtils {
+ @FunctionalInterface
+ private interface ArtifactOrderingStrategy {
+ void apply(
+ Collection<org.apache.maven.artifact.Artifact> artifacts,
+ Collection<? extends DependencyNode> nodes,
+ List<String> trail,
+ DependencyFilter filter);
+ }
+
+ public enum ArtifactOrdering {
+ /**
+ * Depth-first traversal of the dependency graph to convert nodes to
artifacts. This is the original behavior.
+ */
+ DFS(RepositoryUtils::toArtifactsDFS),
+ /**
+ * Breadth-first traversal of the dependency graph, using a List of
Lists to store artifacts by depth, and a stack to keep the dependency trail.
This is the new behavior.
+ */
+ BFS(RepositoryUtils::toArtifactsBFS);
+
+ private ArtifactOrderingStrategy strategy;
+
+ ArtifactOrdering(ArtifactOrderingStrategy strategy) {
+ this.strategy = strategy;
+ }
+
+ public ArtifactOrderingStrategy getStrategy() {
+ return strategy;
+ }
+ }
+
+ private static ArtifactOrdering artifactOrdering = ArtifactOrdering.BFS;
Review Comment:
🔴 **Thread-safety: mutable global state without synchronization.**
This is a non-`volatile`, non-synchronized mutable static field with a
public setter. Maven's concurrent reactor (`-T`) runs dependency resolution on
multiple threads simultaneously. Two problems:
1. **Visibility**: Thread A calls `setArtifactOrdering(DFS)` — Thread B may
never see the write (JMM allows caching in registers/L1).
2. **Mid-traversal corruption**: If the ordering changes while
`toArtifactsDFS` is recursing (it calls the public `toArtifacts` dispatcher —
see next finding), the traversal switches strategy mid-tree.
At minimum, the field should be `volatile`. Better: make it an
`AtomicReference<ArtifactOrdering>` or pass the strategy as a parameter rather
than relying on global mutable state.
```suggestion
private static volatile ArtifactOrdering artifactOrdering =
ArtifactOrdering.BFS;
```
##########
impl/maven-core/src/test/java/org/apache/maven/RepositoryUtilsTest.java:
##########
@@ -32,4 +42,133 @@ void
testToArtifactMethodsReturnNullWhenInputParameterIsNull() {
assertNull(RepositoryUtils.toArtifact((Artifact) null));
assertNull(RepositoryUtils.toArtifact((org.apache.maven.artifact.Artifact)
null));
}
+
+ public void
testToArtifactsCollectionOrderedByNodeDepth(RepositoryUtils.ArtifactOrdering
ordering) {
Review Comment:
🔴 **Dead test: missing `@Test` or `@ParameterizedTest` — JUnit will never
discover or execute this method.**
This method:
1. Has no `@Test` annotation
2. Takes a parameter (`ArtifactOrdering ordering`) which JUnit 5 cannot
inject without a `@ParameterizedTest` + `@EnumSource`
3. **Never uses the `ordering` parameter** — it doesn't call
`setArtifactOrdering(ordering)`, so even if it ran, it would always test the
default (BFS)
4. Hardcodes BFS-order expectations, so it would fail if called with `DFS`
As written, this provides zero test coverage. It should be:
```suggestion
@Test
void testToArtifactsCollectionOrderedByNodeDepth() {
```
And either:
- Remove the `ordering` parameter and test only BFS, or
- Use `@ParameterizedTest @EnumSource(ArtifactOrdering.class)` with
`setArtifactOrdering(ordering)` at the start and separate expected values per
ordering.
##########
impl/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java:
##########
@@ -65,6 +67,46 @@
*/
public class RepositoryUtils {
+ @FunctionalInterface
+ private interface ArtifactOrderingStrategy {
+ void apply(
+ Collection<org.apache.maven.artifact.Artifact> artifacts,
+ Collection<? extends DependencyNode> nodes,
+ List<String> trail,
+ DependencyFilter filter);
+ }
+
+ public enum ArtifactOrdering {
+ /**
+ * Depth-first traversal of the dependency graph to convert nodes to
artifacts. This is the original behavior.
+ */
+ DFS(RepositoryUtils::toArtifactsDFS),
+ /**
+ * Breadth-first traversal of the dependency graph, using a List of
Lists to store artifacts by depth, and a stack to keep the dependency trail.
This is the new behavior.
+ */
+ BFS(RepositoryUtils::toArtifactsBFS);
+
+ private ArtifactOrderingStrategy strategy;
Review Comment:
💡 **Enum field should be `final`.**
The `strategy` field is assigned only in the constructor but not declared
`final`. Since enum constants are singletons, this field will never be
reassigned, but omitting `final` is misleading and allows accidental mutation.
```suggestion
private final ArtifactOrderingStrategy strategy;
```
##########
impl/maven-core/src/test/java/org/apache/maven/RepositoryUtilsTest.java:
##########
@@ -32,4 +42,133 @@ void
testToArtifactMethodsReturnNullWhenInputParameterIsNull() {
assertNull(RepositoryUtils.toArtifact((Artifact) null));
assertNull(RepositoryUtils.toArtifact((org.apache.maven.artifact.Artifact)
null));
}
+
+ public void
testToArtifactsCollectionOrderedByNodeDepth(RepositoryUtils.ArtifactOrdering
ordering) {
+ List<org.apache.maven.artifact.Artifact> artifacts = new ArrayList<>();
+
+ DependencyNode root = createDependencyTree();
+
+ List<String> trail = new ArrayList<>();
+ DependencyFilter filter = null;
+
+ RepositoryUtils.toArtifacts(artifacts, root.getChildren(), trail,
filter);
+
+ String expected =
+ "[gid:zlevel1:jar:1:, gid:ylevel1:jar:1:, gid:xlevel1:jar:1:,
gid:alevel2:jar:1:, gid:blevel2:jar:1:, gid:clevel2:jar:1:,
gid:alevel3:jar:1:]";
+ assertEquals(expected, artifacts.toString());
+
+ String[][] expectedTrails = {
+ {"gid:zlevel1:jar:1"},
+ {"gid:ylevel1:jar:1"},
+ {"gid:xlevel1:jar:1"},
+ {"gid:zlevel1:jar:1", "gid:alevel2:jar:1"},
+ {"gid:ylevel1:jar:1", "gid:blevel2:jar:1"},
+ {"gid:xlevel1:jar:1", "gid:clevel2:jar:1"},
+ {"gid:ylevel1:jar:1", "gid:blevel2:jar:1", "gid:alevel3:jar:1"}
+ };
+
+ assertDependencyTrails(artifacts, expectedTrails);
+ }
+
+ public void
testToArtifactsCollectionOrderedByNodeDepthWithFilter(RepositoryUtils.ArtifactOrdering
ordering) {
Review Comment:
🔴 **Same issue as above** — this method is also never executed by JUnit.
Missing `@Test`/`@ParameterizedTest`, unused `ordering` parameter, hardcoded
BFS expectations.
```suggestion
@Test
void testToArtifactsCollectionOrderedByNodeDepthWithFilter() {
```
##########
impl/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java:
##########
@@ -116,6 +158,14 @@ public static void toArtifacts(
Collection<? extends DependencyNode> nodes,
List<String> trail,
DependencyFilter filter) {
+ artifactOrdering.getStrategy().apply(artifacts, nodes, trail, filter);
+ }
+
+ private static void toArtifactsDFS(
+ Collection<org.apache.maven.artifact.Artifact> artifacts,
+ Collection<? extends DependencyNode> nodes,
+ List<String> trail,
+ DependencyFilter filter) {
for (DependencyNode node : nodes) {
org.apache.maven.artifact.Artifact artifact =
toArtifact(node.getDependency());
Review Comment:
🔴 **Bug: `toArtifactsDFS` recurses through the public dispatcher instead of
calling itself.**
The recursive call inside this method (at the end of the `for` loop, line
181 in the new file) is:
```java
toArtifacts(artifacts, node.getChildren(), nodeTrail, filter);
```
This calls the **public** `toArtifacts` method which dispatches through
`artifactOrdering.getStrategy()`. If the global ordering field is `BFS`, the
DFS method recurses into BFS mid-traversal — producing a corrupted mix of
orderings.
The original code was correct because `toArtifacts` WAS the recursive
method. Now that it's a dispatcher, the DFS implementation must call itself:
```java
toArtifactsDFS(artifacts, node.getChildren(), nodeTrail, filter);
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]