Copilot commented on code in PR #2009:
URL: https://github.com/apache/maven-resolver/pull/2009#discussion_r3645488199


##########
maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultRepositorySystem.java:
##########
@@ -587,6 +670,41 @@ private static boolean isReentrant(RequestTrace trace) {
         return false;
     }
 
+    /**
+     * Combined re-entrancy check using both {@link RequestTrace} ancestry and 
session-scoped
+     * depth tracking. Either mechanism detecting re-entrancy is sufficient to 
skip validation.
+     * <p>
+     * The trace-based check is the primary mechanism and works when callers 
properly propagate
+     * traces. The session-based check is a fallback for callers that rebuild 
the trace chain
+     * from a different tracing system (e.g. Maven 4's trace conversion loses 
the resolver's
+     * re-entrancy marker).
+     *
+     * @param trace   the current request trace (may be {@code null})
+     * @param session the current repository system session
+     * @return {@code true} if this is a re-entrant call, {@code false} if it 
is the outermost call
+     */
+    private static boolean isReentrant(RequestTrace trace, 
RepositorySystemSession session) {
+        return isReentrant(trace) || getReentryDepth(session).get() > 0;
+    }
+
+    /**
+     * Increments the session-scoped re-entrancy depth counter. Must be called 
on every outermost
+     * entry into a public {@code RepositorySystem} method, and the returned 
{@link Runnable} must
+     * be invoked in a {@code finally} block to decrement the counter on exit.
+     *
+     * @param session the current repository system session
+     * @return a {@link Runnable} that decrements the depth counter when 
invoked
+     */
+    private static Runnable enterSessionScope(RepositorySystemSession session) 
{
+        AtomicInteger depth = getReentryDepth(session);
+        depth.incrementAndGet();
+        return depth::decrementAndGet;
+    }
+
+    private static AtomicInteger getReentryDepth(RepositorySystemSession 
session) {
+        return (AtomicInteger) 
session.getData().computeIfAbsent(SESSION_REENTRY_DEPTH_KEY, () -> new 
AtomicInteger(0));
+    }

Review Comment:
   The session-scoped `AtomicInteger` depth counter is shared across all 
threads using the same `RepositorySystemSession`. If the session is used 
concurrently (parallel resolution), one thread can make another thread’s 
*non-reentrant* call look re-entrant (`depth > 0`), causing validation to be 
skipped incorrectly. Consider making the depth tracking thread-scoped (e.g., 
store a `ThreadLocal<Integer>`/`ThreadLocal<AtomicInteger>` in session data, or 
store a per-thread counter keyed by `Thread.currentThread()`/thread id with 
proper cleanup) so only true call-stack re-entrancy on the same thread 
suppresses validation. Update the Javadoc to reflect the chosen semantics.



##########
maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultRepositorySystemReentrancyTest.java:
##########
@@ -303,4 +312,120 @@ void outerCallWithNullTraceStillStampsMarker() throws 
Exception {
         system.resolveVersionRange(session, innerRequest);
         assertEquals(countBefore, validationCount.get(), "Re-entrant call 
should skip validation");
     }
+
+    @Test
+    void sessionScopedDetectionSkipsValidationWhenTraceChainIsBroken() throws 
Exception {
+        // Simulates Maven 4's flow where the model builder converts between 
Maven API traces
+        // and resolver traces via RequestTraceHelper, losing the 
REPOSITORY_SYSTEM_CALL marker.
+        //
+        // The DependencyCollector, called from within collectDependencies, 
re-enters
+        // RepositorySystem.resolveVersionRange with a FRESH trace (no marker 
in ancestry)
+        // and an uninterpolated expression like ${project.version}. Without 
session-scoped
+        // detection, the validator would reject the expression; with it, the 
call is
+        // detected as re-entrant and validation is skipped.
+        AtomicReference<DefaultRepositorySystem> systemRef = new 
AtomicReference<>();
+
+        DependencyCollector reentrantCollector = (s, request) -> {
+            // Inside collectDependencies, simulate a re-entrant call with a 
FRESH trace
+            // (no marker in ancestry — this is the broken path) and an 
uninterpolated
+            // expression. If session-scoped detection fails, the validator 
rejects this.
+            VersionRangeRequest innerRequest = new VersionRangeRequest(
+                    new DefaultArtifact("g:inner:${project.version}"), 
Collections.emptyList(), null);
+            // Fresh trace — no REPOSITORY_SYSTEM_CALL marker (simulates 
Maven's trace conversion)
+            innerRequest.setTrace(RequestTrace.newChild(null, 
"MavenModelResolver"));
+            try {
+                systemRef.get().resolveVersionRange(s, innerRequest);
+            } catch (Exception e) {
+                fail("Re-entrant call with broken trace chain should succeed 
via session-scoped detection: " + e);
+            }

Review Comment:
   Catching `Exception` and concatenating `e` into the failure message drops 
the stack trace from the assertion output, which makes failures harder to 
diagnose. Prefer `fail(message, e)` (or an assertion that preserves the 
throwable) so the original exception is reported with full context.



-- 
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]

Reply via email to