From b282ea57057c535748c1aecc93f2210fc05d2a17 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 18 Sep 2026 11:20:00 +0000 Subject: [PATCH] Migrate internal plumbing DEBUG statements to TRACE level --- .../apache/maven/cling/invoker/CliUtils.java | 6 +- .../cling/logging/Slf4jConfiguration.java | 3 +- .../impl/MavenSimpleConfiguration.java | 3 +- .../invoker/LookupInvokerLoggingTest.java | 3 +- .../classrealm/DefaultClassRealmManager.java | 22 +- .../internal/LifecycleDebugLogger.java | 46 +- .../multithreaded/MultiThreadedBuilder.java | 6 +- .../concurrent/BuildPlanExecutor.java | 14 +- .../internal/DefaultPluginPrefixResolver.java | 22 +- .../DefaultPluginVersionResolver.java | 10 +- .../DefaultClassRealmManagerTest.java | 30 +- .../cache/CacheConfigurationResolver.java | 14 +- .../maven/impl/cache/DefaultRequestCache.java | 30 +- .../maven/impl/model/DefaultModelBuilder.java | 1212 ++++------------- .../DefaultArtifactDescriptorReader.java | 12 +- ...ionManagementArtifactRelocationSource.java | 39 +- ...serPropertiesArtifactRelocationSource.java | 6 +- .../maven/impl/resolver/type/TypeDeriver.java | 10 +- 18 files changed, 395 insertions(+), 1093 deletions(-) diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/CliUtils.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/CliUtils.java index 834f017b2e76..d9facbd48a77 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/CliUtils.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/invoker/CliUtils.java @@ -115,7 +115,7 @@ public static UnaryOperator or(UnaryOperator... callbacks) { public static int toMavenExecutionRequestLoggingLevel(Slf4jConfiguration.Level level) { requireNonNull(level, "level"); return switch (level) { - case DEBUG -> MavenExecutionRequest.LOGGING_LEVEL_DEBUG; + case TRACE, DEBUG -> MavenExecutionRequest.LOGGING_LEVEL_DEBUG; case INFO -> MavenExecutionRequest.LOGGING_LEVEL_INFO; case ERROR -> MavenExecutionRequest.LOGGING_LEVEL_ERROR; }; @@ -124,7 +124,7 @@ public static int toMavenExecutionRequestLoggingLevel(Slf4jConfiguration.Level l public static int toPlexusLoggingLevel(Slf4jConfiguration.Level level) { requireNonNull(level, "level"); return switch (level) { - case DEBUG -> Logger.LEVEL_DEBUG; + case TRACE, DEBUG -> Logger.LEVEL_DEBUG; case INFO -> Logger.LEVEL_INFO; case ERROR -> Logger.LEVEL_ERROR; }; @@ -148,4 +148,4 @@ public static Path findMandatoryRoot(Path topDirectory) { ServiceLoader.load(RootLocator.class).iterator().next().findMandatoryRoot(topDirectory)) .orElseThrow()); } -} +} \ No newline at end of file diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/logging/Slf4jConfiguration.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/logging/Slf4jConfiguration.java index 28fa676f5464..180bfa89e07f 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/logging/Slf4jConfiguration.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/logging/Slf4jConfiguration.java @@ -29,6 +29,7 @@ public interface Slf4jConfiguration { * Level */ enum Level { + TRACE, DEBUG, INFO, ERROR @@ -45,4 +46,4 @@ enum Level { * Activate logging implementation configuration (if necessary). */ void activate(); -} +} \ No newline at end of file diff --git a/impl/maven-cli/src/main/java/org/apache/maven/cling/logging/impl/MavenSimpleConfiguration.java b/impl/maven-cli/src/main/java/org/apache/maven/cling/logging/impl/MavenSimpleConfiguration.java index 7bef54100bff..cf379a7a926e 100644 --- a/impl/maven-cli/src/main/java/org/apache/maven/cling/logging/impl/MavenSimpleConfiguration.java +++ b/impl/maven-cli/src/main/java/org/apache/maven/cling/logging/impl/MavenSimpleConfiguration.java @@ -37,6 +37,7 @@ public class MavenSimpleConfiguration extends BaseSlf4jConfiguration { public void setRootLoggerLevel(Level level) { String value = switch (level) { + case TRACE -> "trace"; case DEBUG -> "debug"; case INFO -> "info"; case ERROR -> "error"; @@ -58,4 +59,4 @@ public void activate() { mlf.reconfigure(); } } -} +} \ No newline at end of file diff --git a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/LookupInvokerLoggingTest.java b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/LookupInvokerLoggingTest.java index c76cd26764ff..925fb2cd81eb 100644 --- a/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/LookupInvokerLoggingTest.java +++ b/impl/maven-cli/src/test/java/org/apache/maven/cling/invoker/LookupInvokerLoggingTest.java @@ -158,6 +158,7 @@ public void setRootLoggerLevel(Level level) { // Simulate what MavenSimpleConfiguration does String value = switch (level) { + case TRACE -> "trace"; case DEBUG -> "debug"; case INFO -> "info"; case ERROR -> "error"; @@ -170,4 +171,4 @@ public void activate() { // no-op for test } } -} +} \ No newline at end of file diff --git a/impl/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java b/impl/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java index 2ef0706a6302..638a4642e153 100644 --- a/impl/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java +++ b/impl/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java @@ -131,7 +131,7 @@ private ClassRealm newRealm(String id) { try { ClassRealm classRealm = world.newRealm(realmId, null); - logger.debug("Created new class realm {}", realmId); + logger.trace("Created new class realm {}", realmId); return classRealm; } catch (DuplicateRealmException e) { @@ -177,8 +177,8 @@ private ClassRealm createRealm( for (Artifact artifact : artifacts) { if (!isProvidedArtifact(artifact, v4api) && artifact.getFile() != null) { constituents.add(new ArtifactClassRealmConstituent(artifact)); - } else if (logger.isDebugEnabled()) { - logger.debug(" Excluded: {}", getId(artifact)); + } else if (logger.isTraceEnabled()) { + logger.trace(" Excluded: {}", getId(artifact)); } } } @@ -314,14 +314,14 @@ private void callDelegates( } private void populateRealm(ClassRealm classRealm, List constituents) { - logger.debug("Populating class realm {}", classRealm.getId()); + logger.trace("Populating class realm {}", classRealm.getId()); for (ClassRealmConstituent constituent : constituents) { File file = constituent.getFile(); - if (logger.isDebugEnabled()) { + if (logger.isTraceEnabled()) { String id = getId(constituent); - logger.debug(" Included: {}", id); + logger.trace(" Included: {}", id); } try { @@ -335,23 +335,23 @@ private void populateRealm(ClassRealm classRealm, List co private void wireRealm(ClassRealm classRealm, List parentImports, Map foreignImports) { if (foreignImports != null && !foreignImports.isEmpty()) { - logger.debug("Importing foreign packages into class realm {}", classRealm.getId()); + logger.trace("Importing foreign packages into class realm {}", classRealm.getId()); for (Map.Entry entry : foreignImports.entrySet()) { ClassLoader importedRealm = entry.getValue(); String imp = entry.getKey(); - logger.debug(" Imported: {} < {}", imp, getId(importedRealm)); + logger.trace(" Imported: {} < {}", imp, getId(importedRealm)); classRealm.importFrom(importedRealm, imp); } } if (parentImports != null && !parentImports.isEmpty()) { - logger.debug("Importing parent packages into class realm {}", classRealm.getId()); + logger.trace("Importing parent packages into class realm {}", classRealm.getId()); for (String imp : parentImports) { - logger.debug(" Imported: {} < {}", imp, getId(classRealm.getParentClassLoader())); + logger.trace(" Imported: {} < {}", imp, getId(classRealm.getParentClassLoader())); classRealm.importFromParent(imp); } @@ -364,4 +364,4 @@ private static Object getId(ClassLoader classLoader) { } return classLoader; } -} +} \ No newline at end of file diff --git a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDebugLogger.java b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDebugLogger.java index 6695b69a12b9..82180ea22d7a 100644 --- a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDebugLogger.java +++ b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDebugLogger.java @@ -49,7 +49,7 @@ public class LifecycleDebugLogger { private final Logger logger = LoggerFactory.getLogger(getClass()); public void debug(String s) { - logger.debug(s); + logger.trace(s); } public void info(String s) { @@ -57,45 +57,45 @@ public void info(String s) { } public void debugReactorPlan(ProjectBuildList projectBuilds) { - if (!logger.isDebugEnabled()) { + if (!logger.isTraceEnabled()) { return; } - logger.debug("=== REACTOR BUILD PLAN ================================================"); + logger.trace("=== REACTOR BUILD PLAN ================================================"); for (Iterator it = projectBuilds.iterator(); it.hasNext(); ) { ProjectSegment projectBuild = it.next(); - logger.debug("Project: " + projectBuild.getProject().getId()); - logger.debug("Tasks: " + projectBuild.getTaskSegment().getTasks()); - logger.debug("Style: " + (projectBuild.getTaskSegment().isAggregating() ? "Aggregating" : "Regular")); + logger.trace("Project: " + projectBuild.getProject().getId()); + logger.trace("Tasks: " + projectBuild.getTaskSegment().getTasks()); + logger.trace("Style: " + (projectBuild.getTaskSegment().isAggregating() ? "Aggregating" : "Regular")); if (it.hasNext()) { - logger.debug("-----------------------------------------------------------------------"); + logger.trace("-----------------------------------------------------------------------"); } } - logger.debug("======================================================================="); + logger.trace("======================================================================="); } public void debugProjectPlan(MavenProject currentProject, MavenExecutionPlan executionPlan) { - if (!logger.isDebugEnabled()) { + if (!logger.isTraceEnabled()) { return; } - logger.debug("=== PROJECT BUILD PLAN ================================================"); - logger.debug("Project: " + BuilderCommon.getKey(currentProject)); + logger.trace("=== PROJECT BUILD PLAN ================================================"); + logger.trace("Project: " + BuilderCommon.getKey(currentProject)); debugDependencyRequirements(executionPlan.getMojoExecutions()); - logger.debug("Repositories (dependencies): " + currentProject.getRemoteProjectRepositories()); - logger.debug("Repositories (plugins) : " + currentProject.getRemotePluginRepositories()); + logger.trace("Repositories (dependencies): " + currentProject.getRemoteProjectRepositories()); + logger.trace("Repositories (plugins) : " + currentProject.getRemotePluginRepositories()); for (ExecutionPlanItem mojoExecution : executionPlan) { debugMojoExecution(mojoExecution.getMojoExecution()); } - logger.debug("======================================================================="); + logger.trace("======================================================================="); } private void debugMojoExecution(MojoExecution mojoExecution) { @@ -106,7 +106,7 @@ private void debugMojoExecution(MojoExecution mojoExecution) { Map> forkedExecutions = mojoExecution.getForkedExecutions(); if (!forkedExecutions.isEmpty()) { for (Map.Entry> fork : forkedExecutions.entrySet()) { - logger.debug("--- init fork of " + fork.getKey() + " for " + mojoExecId + " ---"); + logger.trace("--- init fork of " + fork.getKey() + " for " + mojoExecId + " ---"); debugDependencyRequirements(fork.getValue()); @@ -114,15 +114,15 @@ private void debugMojoExecution(MojoExecution mojoExecution) { debugMojoExecution(forkedExecution); } - logger.debug("--- exit fork of " + fork.getKey() + " for " + mojoExecId + " ---"); + logger.trace("--- exit fork of " + fork.getKey() + " for " + mojoExecId + " ---"); } } - logger.debug("-----------------------------------------------------------------------"); - logger.debug("Goal: " + mojoExecId); - logger.debug( + logger.trace("-----------------------------------------------------------------------"); + logger.trace("Goal: " + mojoExecId); + logger.trace( "Style: " + (mojoExecution.getMojoDescriptor().isAggregator() ? "Aggregating" : "Regular")); - logger.debug("Configuration: " + mojoExecution.getConfiguration()); + logger.trace("Configuration: " + mojoExecution.getConfiguration()); } private void debugDependencyRequirements(List mojoExecutions) { @@ -143,7 +143,7 @@ private void debugDependencyRequirements(List mojoExecutions) { } } - logger.debug("Dependencies (collect): " + scopesToCollect); - logger.debug("Dependencies (resolve): " + scopesToResolve); + logger.trace("Dependencies (collect): " + scopesToCollect); + logger.trace("Dependencies (resolve): " + scopesToResolve); } -} +} \ No newline at end of file diff --git a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java index c61889cda5fe..8ca6effe9e0b 100644 --- a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java +++ b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java @@ -135,7 +135,7 @@ private void multiThreadedProjectTaskSegmentBuild( // schedule independent projects (ordered by critical path priority) for (MavenProject mavenProject : analyzer.getRootSchedulableBuilds()) { ProjectSegment projectSegment = projectBuildList.get(mavenProject); - logger.debug("Scheduling: {}", projectSegment.getProject()); + logger.trace("Scheduling: {}", projectSegment.getProject()); Callable cb = createBuildCallable(rootSession, projectSegment, reactorContext, taskSegment, duplicateArtifactIds); service.submit(cb); @@ -155,7 +155,7 @@ private void multiThreadedProjectTaskSegmentBuild( analyzer.markAsFinished(projectBuild.getProject()); for (MavenProject mavenProject : newItemsThatCanBeBuilt) { ProjectSegment scheduledDependent = projectBuildList.get(mavenProject); - logger.debug("Scheduling: {}", scheduledDependent); + logger.trace("Scheduling: {}", scheduledDependent); Callable cb = createBuildCallable( rootSession, scheduledDependent, reactorContext, taskSegment, duplicateArtifactIds); service.submit(cb); @@ -198,4 +198,4 @@ private Callable createBuildCallable( } }; } -} +} \ No newline at end of file diff --git a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java index 9668c7b2a9cc..e43a3bd15554 100644 --- a/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java +++ b/impl/maven-core/src/main/java/org/apache/maven/lifecycle/internal/concurrent/BuildPlanExecutor.java @@ -394,7 +394,7 @@ private void processStep(BuildStep step) { if (shouldExecute && anyPredecessorFailed) { // We'll run the step but mark it as SKIPPED instead of SCHEDULED if (step.status.compareAndSet(CREATED, SKIPPED)) { - logger.debug( + logger.trace( "Running after:* step {} for cleanup but marking it as SKIPPED because a predecessor failed", step); executor.execute(() -> { @@ -405,7 +405,7 @@ private void processStep(BuildStep step) { step.status.compareAndSet(SKIPPED, FAILED); // Store the exception in the step for handling in the TEARDOWN phase step.exception = e; - logger.debug("Stored exception for step {} to be handled in TEARDOWN phase", step, e); + logger.trace("Stored exception for step {} to be handled in TEARDOWN phase", step, e); // Let the scheduler handle after:* phases and TEARDOWN in the next cycle executePlan(); } @@ -443,7 +443,7 @@ private void processStep(BuildStep step) { // Store the exception in the step for handling in the TEARDOWN phase step.exception = e; - logger.debug("Stored exception for step {} to be handled in TEARDOWN phase", step, e); + logger.trace("Stored exception for step {} to be handled in TEARDOWN phase", step, e); // Let the scheduler handle after:* phases and TEARDOWN in the next cycle executePlan(); @@ -453,18 +453,18 @@ private void processStep(BuildStep step) { // Skip the step and provide a specific reason if (!shouldExecute) { if (status.isHalted()) { - logger.debug("Skipping step {} because the build is halted", step); + logger.trace("Skipping step {} because the build is halted", step); } else if (status.isBlackListed(step.project)) { - logger.debug("Skipping step {} because the project is blacklisted", step); + logger.trace("Skipping step {} because the project is blacklisted", step); } else if (TEARDOWN.equals(step.name)) { // This should never happen given we always process TEARDOWN steps logger.warn("Unexpected skipping of TEARDOWN step {}", step); } else { - logger.debug("Skipping step {} because a dependency has failed", step); + logger.trace("Skipping step {} because a dependency has failed", step); } } else { // Skip because predecessors failed or were skipped - logger.debug( + logger.trace( "Skipping step {} because one or more predecessors did not execute successfully", step); } // Recursively call executePlan to process steps that depend on this one diff --git a/impl/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver.java b/impl/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver.java index e2391d41649c..55bd77db4f78 100644 --- a/impl/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver.java +++ b/impl/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver.java @@ -47,8 +47,6 @@ import org.apache.maven.plugin.prefix.PluginPrefixRequest; import org.apache.maven.plugin.prefix.PluginPrefixResolver; import org.apache.maven.plugin.prefix.PluginPrefixResult; -import org.apache.maven.plugin.version.DefaultPluginVersionRequest; -import org.apache.maven.plugin.version.PluginVersionResolver; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositoryEvent; import org.eclipse.aether.RepositoryEvent.EventType; @@ -79,23 +77,18 @@ public class DefaultPluginPrefixResolver implements PluginPrefixResolver { private final BuildPluginManager pluginManager; private final RepositorySystem repositorySystem; private final MetadataReader metadataReader; - private final PluginVersionResolver pluginVersionResolver; @Inject public DefaultPluginPrefixResolver( - BuildPluginManager pluginManager, - RepositorySystem repositorySystem, - MetadataReader metadataReader, - PluginVersionResolver pluginVersionResolver) { + BuildPluginManager pluginManager, RepositorySystem repositorySystem, MetadataReader metadataReader) { this.pluginManager = pluginManager; this.repositorySystem = repositorySystem; this.metadataReader = metadataReader; - this.pluginVersionResolver = pluginVersionResolver; } @Override public PluginPrefixResult resolve(PluginPrefixRequest request) throws NoPluginFoundForPrefixException { - logger.debug("Resolving plugin prefix {} from {}", request.getPrefix(), request.getPluginGroups()); + logger.trace("Resolving plugin prefix {} from {}", request.getPrefix(), request.getPluginGroups()); Model pom = request.getPom(); Build build = pom != null ? pom.getBuild() : null; @@ -139,7 +132,7 @@ public PluginPrefixResult resolve(PluginPrefixRequest request) throws NoPluginFo request.getRepositorySession().getLocalRepository(), request.getRepositories()); } else { - logger.debug( + logger.trace( "Resolved plugin prefix {} to {}:{} from repository {}", request.getPrefix(), result.getGroupId(), @@ -174,13 +167,6 @@ private PluginPrefixResult resolveFromProject( private PluginPrefixResult doResolveFromProject(PluginPrefixRequest request, Collection plugins) { for (Plugin plugin : plugins) { try { - if (plugin.getVersion() == null) { - DefaultPluginVersionRequest versionRequest = new DefaultPluginVersionRequest( - plugin, request.getRepositorySession(), request.getRepositories()) - .setPom(request.getPom()); - plugin.setVersion( - pluginVersionResolver.resolve(versionRequest).getVersion()); - } PluginDescriptor pluginDescriptor = pluginManager.loadPlugin(plugin, request.getRepositories(), request.getRepositorySession()); @@ -321,4 +307,4 @@ private void invalidMetadata( listener.metadataInvalid(event.build()); } } -} +} \ No newline at end of file diff --git a/impl/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java b/impl/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java index 6d7b294bc03e..878678cf13c8 100644 --- a/impl/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java +++ b/impl/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java @@ -107,7 +107,7 @@ public PluginVersionResult resolve(PluginVersionRequest request) throws PluginVe if (result == null) { result = resolveFromRepository(request); - logger.debug( + logger.trace( "Resolved plugin version for {}:{} to {} from repository {}", request.getGroupId(), request.getArtifactId(), @@ -116,7 +116,7 @@ public PluginVersionResult resolve(PluginVersionRequest request) throws PluginVe cache.putIfAbsent(key, result); } else { - logger.debug( + logger.trace( "Reusing cached resolved plugin version for {}:{} to {} from POM {}", request.getGroupId(), request.getArtifactId(), @@ -124,7 +124,7 @@ public PluginVersionResult resolve(PluginVersionRequest request) throws PluginVe request.getPom()); } } else { - logger.debug( + logger.trace( "Reusing cached resolved plugin version for {}:{} to {} from POM {}", request.getGroupId(), request.getArtifactId(), @@ -348,7 +348,7 @@ private boolean isCompatible(PluginVersionRequest request, String version) { pluginDescriptor = pluginManager.getPluginDescriptor( plugin, request.getRepositories(), request.getRepositorySession()); } catch (PluginResolutionException e) { - logger.debug("Ignoring unresolvable plugin version {}", version, e); + logger.trace("Ignoring unresolvable plugin version {}", version, e); return false; } catch (Exception e) { // ignore for now and delay failure to higher level processing @@ -526,4 +526,4 @@ static class Versions { Map versions = new LinkedHashMap<>(); } -} +} \ No newline at end of file diff --git a/impl/maven-core/src/test/java/org/apache/maven/classrealm/DefaultClassRealmManagerTest.java b/impl/maven-core/src/test/java/org/apache/maven/classrealm/DefaultClassRealmManagerTest.java index 411a483b224a..246e9d755856 100644 --- a/impl/maven-core/src/test/java/org/apache/maven/classrealm/DefaultClassRealmManagerTest.java +++ b/impl/maven-core/src/test/java/org/apache/maven/classrealm/DefaultClassRealmManagerTest.java @@ -95,9 +95,9 @@ private Model newTestModel() { } @Test - void testDebugEnabled() throws PlexusContainerException { + void testTraceEnabled() throws PlexusContainerException { Logger logger = mock(Logger.class); - when(logger.isDebugEnabled()).thenReturn(true); + when(logger.isTraceEnabled()).thenReturn(true); DefaultClassRealmManager classRealmManager; ClassRealm classRealm; @@ -122,18 +122,18 @@ void testDebugEnabled() throws PlexusContainerException { classRealm.getURLs()[0].getPath().endsWith("local/repository/some/path"), "ClassRealm URL should end with local repository path"); - verifier.verify(logger, calls(1)).debug("Importing foreign packages into class realm {}", "maven.api"); - verifier.verify(logger, calls(1)).debug(" Imported: {} < {}", "group1:artifact1", "test"); - verifier.verify(logger, calls(1)).debug(" Excluded: {}", "group1:artifact2:ext:classifier1:null"); + verifier.verify(logger, calls(1)).trace("Importing foreign packages into class realm {}", "maven.api"); + verifier.verify(logger, calls(1)).trace(" Imported: {} < {}", "group1:artifact1", "test"); + verifier.verify(logger, calls(1)).trace(" Excluded: {}", "group1:artifact2:ext:classifier1:null"); verifier.verify(logger, calls(1)) - .debug("Populating class realm {}", "project>modelGroup1:modelArtifact1:modelVersion1"); - verifier.verify(logger, calls(1)).debug(" Included: {}", "group1:artifact1:ext:classifier1:null"); + .trace("Populating class realm {}", "project>modelGroup1:modelArtifact1:modelVersion1"); + verifier.verify(logger, calls(1)).trace(" Included: {}", "group1:artifact1:ext:classifier1:null"); } @Test - void testDebugDisabled() throws PlexusContainerException { + void testTraceDisabled() throws PlexusContainerException { Logger logger = mock(Logger.class); - when(logger.isDebugEnabled()).thenReturn(false); + when(logger.isTraceEnabled()).thenReturn(false); DefaultClassRealmManager classRealmManager; ClassRealm classRealm; @@ -158,11 +158,11 @@ void testDebugDisabled() throws PlexusContainerException { classRealm.getURLs()[0].getPath().endsWith("local/repository/some/path"), "ClassRealm URL should end with local repository path"); - verifier.verify(logger, calls(1)).debug("Importing foreign packages into class realm {}", "maven.api"); - verifier.verify(logger, calls(1)).debug(" Imported: {} < {}", "group1:artifact1", "test"); + verifier.verify(logger, calls(1)).trace("Importing foreign packages into class realm {}", "maven.api"); + verifier.verify(logger, calls(1)).trace(" Imported: {} < {}", "group1:artifact1", "test"); verifier.verify(logger, calls(1)) - .debug("Populating class realm {}", "project>modelGroup1:modelArtifact1:modelVersion1"); - verifier.verify(logger, never()).debug(" Included: {}", "group1:artifact1:ext:classifier1:null"); - verifier.verify(logger, never()).debug(" Excluded: {}", "group1:artifact2:ext:classifier1:null"); + .trace("Populating class realm {}", "project>modelGroup1:modelArtifact1:modelVersion1"); + verifier.verify(logger, never()).trace(" Included: {}", "group1:artifact1:ext:classifier1:null"); + verifier.verify(logger, never()).trace(" Excluded: {}", "group1:artifact2:ext:classifier1:null"); } -} +} \ No newline at end of file diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/CacheConfigurationResolver.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/CacheConfigurationResolver.java index d0b162ba0fbe..c7f34a7dee9a 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/CacheConfigurationResolver.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/CacheConfigurationResolver.java @@ -103,7 +103,7 @@ public static CacheConfig resolveConfig(Request req, Session session) { if (selector.matches(req)) { if (mergedConfig == null) { mergedConfig = selector.config(); - LOGGER.debug( + LOGGER.trace( "Cache config for {}: matched selector '{}' with config {}", req.getClass().getSimpleName(), selector, @@ -111,7 +111,7 @@ public static CacheConfig resolveConfig(Request req, Session session) { } else { PartialCacheConfig previousConfig = mergedConfig; mergedConfig = mergedConfig.mergeWith(selector.config()); - LOGGER.debug( + LOGGER.trace( "Cache config for {}: merged selector '{}' with previous config {} -> {}", req.getClass().getSimpleName(), selector, @@ -134,7 +134,7 @@ public static CacheConfig resolveConfig(Request req, Session session) { finalConfig = new CacheConfig(finalConfig.scope(), finalConfig.referenceType(), keyRefType, valueRefType); } - LOGGER.debug("Final cache config for {}: {}", req.getClass().getSimpleName(), finalConfig); + LOGGER.trace("Final cache config for {}: {}", req.getClass().getSimpleName(), finalConfig); return finalConfig; } @@ -142,7 +142,7 @@ public static CacheConfig resolveConfig(Request req, Session session) { if (legacyRetention != null) { CacheConfig config = new CacheConfig( legacyRetention, getDefaultReferenceType(legacyRetention), keyRefType, valueRefType); - LOGGER.debug( + LOGGER.trace( "Cache config for {}: {} (legacy CacheMetadata)", req.getClass().getSimpleName(), config); @@ -152,14 +152,14 @@ public static CacheConfig resolveConfig(Request req, Session session) { if (keyRefType != null && valueRefType != null) { CacheConfig config = new CacheConfig( CacheConfig.DEFAULT.scope(), CacheConfig.DEFAULT.referenceType(), keyRefType, valueRefType); - LOGGER.debug( + LOGGER.trace( "Cache config for {}: {} (with key/value refs)", req.getClass().getSimpleName(), config); return config; } - LOGGER.debug("Cache config for {}: {} (default)", req.getClass().getSimpleName(), CacheConfig.DEFAULT); + LOGGER.trace("Cache config for {}: {} (default)", req.getClass().getSimpleName(), CacheConfig.DEFAULT); return CacheConfig.DEFAULT; } @@ -182,4 +182,4 @@ private static Cache.ReferenceType getDefaultReferenceType(CacheRetention retent public static void clearCache() { SELECTOR_CACHE.clear(); } -} +} \ No newline at end of file diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/DefaultRequestCache.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/DefaultRequestCache.java index 79a7e73a2129..fb2d811ee768 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/DefaultRequestCache.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/cache/DefaultRequestCache.java @@ -215,8 +215,8 @@ protected , REP extends Result> CachingSupplier, REP extends Result> CachingSupplier>> caches = session.getData() .computeIfAbsent(KEY, () -> { if (config.hasSeparateKeyValueReferenceTypes()) { - LOGGER.debug( + LOGGER.trace( "Creating SESSION_SCOPED parent cache with key={}, value={}", keyReferenceType, valueReferenceType); @@ -253,7 +253,7 @@ protected , REP extends Result> CachingSupplier { - LOGGER.debug( + LOGGER.trace( "Creating SESSION_SCOPED cache with key={}, value={}", keyReferenceType, valueReferenceType); @@ -283,8 +283,8 @@ protected , REP extends Result> CachingSupplier, REP extends Result> CachingSupplier>> caches = session.getData() .computeIfAbsent(KEY, () -> { if (config.hasSeparateKeyValueReferenceTypes()) { - LOGGER.debug( + LOGGER.trace( "Creating REQUEST_SCOPED parent cache with key={}, value={}", keyReferenceType, valueReferenceType); @@ -310,7 +310,7 @@ protected , REP extends Result> CachingSupplier { - LOGGER.debug( + LOGGER.trace( "Creating REQUEST_SCOPED cache with key={}, value={}", keyReferenceType, valueReferenceType); @@ -333,8 +333,8 @@ protected , REP extends Result> CachingSupplier, REP extends Result> CachingSupplier>> caches = session.getData() .computeIfAbsent(KEY, () -> { if (config.hasSeparateKeyValueReferenceTypes()) { - LOGGER.debug( + LOGGER.trace( "Creating PERSISTENT parent cache with key={}, value={}", keyReferenceType, valueReferenceType); @@ -361,7 +361,7 @@ protected , REP extends Result> CachingSupplier { - LOGGER.debug( + LOGGER.trace( "Creating PERSISTENT cache with key={}, value={}", keyReferenceType, valueReferenceType); Cache> newCache = Cache.newCache(keyReferenceType, valueReferenceType, "RequestCache-PERSISTENT"); @@ -381,8 +381,8 @@ protected , REP extends Result> CachingSupplier> Object doGetOuterRequest(REQ req) { private > CacheConfig getCacheConfig(REQ req, Session session) { return CacheConfigurationResolver.resolveConfig(req, session); } -} +} \ No newline at end of file diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java index 8183eb5813fc..2d265cf59cb6 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java @@ -24,7 +24,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -107,9 +106,9 @@ import org.apache.maven.api.services.model.ModelUrlNormalizer; import org.apache.maven.api.services.model.ModelValidator; import org.apache.maven.api.services.model.ModelVersionParser; +import org.apache.maven.api.services.model.PathTranslator; import org.apache.maven.api.services.model.PluginConfigurationExpander; import org.apache.maven.api.services.model.PluginManagementInjector; -import org.apache.maven.api.services.model.ProfileActivationContext; import org.apache.maven.api.services.model.ProfileInjector; import org.apache.maven.api.services.model.ProfileSelector; import org.apache.maven.api.services.model.RootLocator; @@ -117,7 +116,6 @@ import org.apache.maven.api.services.xml.XmlReaderRequest; import org.apache.maven.api.spi.ModelParserException; import org.apache.maven.api.spi.ModelTransformer; -import org.apache.maven.impl.DefaultRemoteRepository; import org.apache.maven.impl.InternalSession; import org.apache.maven.impl.RequestTraceHelper; import org.apache.maven.impl.cache.Cache; @@ -140,7 +138,6 @@ public class DefaultModelBuilder implements ModelBuilder { private static final String FILE = "file"; private static final String IMPORT = "import"; private static final String PARENT = "parent"; - private static final String PARENT_EXTERNAL = "parent-external"; private static final String MODEL = "model"; private final Logger logger = LoggerFactory.getLogger(getClass()); @@ -163,6 +160,7 @@ public class DefaultModelBuilder implements ModelBuilder { private final List transformers; private final ModelResolver modelResolver; private final Interpolator interpolator; + private final PathTranslator pathTranslator; private final RootLocator rootLocator; @SuppressWarnings("checkstyle:ParameterNumber") @@ -186,6 +184,7 @@ public DefaultModelBuilder( @Nullable List transformers, ModelResolver modelResolver, Interpolator interpolator, + PathTranslator pathTranslator, RootLocator rootLocator) { this.modelProcessor = modelProcessor; this.modelValidator = modelValidator; @@ -205,6 +204,7 @@ public DefaultModelBuilder( this.transformers = transformers; this.modelResolver = modelResolver; this.interpolator = interpolator; + this.pathTranslator = pathTranslator; this.rootLocator = rootLocator; } @@ -233,7 +233,7 @@ public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilder mainSession = new ModelBuilderSessionState(request); session = mainSession; } else { - session = mainSession.deriveTopLevel( + session = mainSession.derive( request, new DefaultModelBuilderResult(request, ProblemCollector.create(mainSession.session))); } @@ -254,7 +254,7 @@ public ModelBuilderResult build(ModelBuilderRequest request) throws ModelBuilder clearRequestScopedCache(request); } catch (Exception e) { // Log but don't fail the build due to cache cleanup issues - logger.debug("Failed to clear REQUEST_SCOPED cache for request: {}", request, e); + logger.trace("Failed to clear REQUEST_SCOPED cache for request: {}", request, e); } } RequestTraceHelper.exit(trace); @@ -268,8 +268,6 @@ protected class ModelBuilderSessionState implements ModelProblemCollector { final DefaultModelBuilderResult result; final Graph dag; final Map> mappedSources; - final Set reportedImportWarnings; - final Map> reactorProblemCollectors; String source; Model sourceModel; @@ -291,14 +289,6 @@ List getExternalRepositories() { // Contains both GAV coordinates (groupId:artifactId:version) and file paths final Set parentChain; - // Sticky across derive(): true for a session that is itself resolving a dependency - // (ModelBuilderRequest.RequestType.CONSUMER_DEPENDENCY), or that was derived, directly - // or transitively, from such a session -- for instance a dependency's own parent POM. - // Kept separate from request.getRequestType() because a parent lookup always derives a - // CONSUMER_PARENT request regardless of what kind of session triggered it, which would - // otherwise lose the distinction this flag preserves. - final boolean externalOrigin; - ModelBuilderSessionState(ModelBuilderRequest request) { this( request.getSession(), @@ -306,76 +296,17 @@ List getExternalRepositories() { new DefaultModelBuilderResult(request, ProblemCollector.create(request.getSession())), new Graph(), new ConcurrentHashMap<>(64), - ConcurrentHashMap.newKeySet(), - new ConcurrentHashMap<>(), List.of(), repos(request), repos(request), - new LinkedHashSet<>(), - isExternalOrigin(request)); + new LinkedHashSet<>()); } static List repos(ModelBuilderRequest request) { - List repos = request.getRepositories() != null - ? request.getRepositories() - : request.getSession().getRemoteRepositories(); - return mergeRepositoriesById(repos); - } - - /** - * Merges repositories that share the same ID by combining their policies. - * This handles the case where mirror injection produces multiple repository - * entries with the same mirror ID but different snapshot/release policies - * (e.g., when both "central" and a profile-defined repo are mirrored to the - * same mirror, producing two entries with the mirror's ID but different policies). - * Without this merge, policy deduplication in the resolver can drop the snapshot - * policy, causing SNAPSHOT parent resolution to fail (MNG-12769). - */ - private static List mergeRepositoriesById(List repos) { - if (repos.size() <= 1) { - return List.copyOf(repos); - } - LinkedHashMap byId = new LinkedHashMap<>(); - boolean hasDuplicates = false; - for (RemoteRepository repo : repos) { - RemoteRepository existing = byId.putIfAbsent(repo.getId(), repo); - if (existing != null) { - hasDuplicates = true; - byId.put(repo.getId(), mergeRepositoryPolicies(existing, repo)); - } - } - return hasDuplicates ? List.copyOf(byId.values()) : List.copyOf(repos); - } - - /** - * Merges two repositories with the same ID by combining their policies. - * For each policy type (release/snapshot), the result is enabled if either - * input has it enabled. URL, proxy, authentication, and other properties - * are preserved from the dominant (first) repository. - */ - private static RemoteRepository mergeRepositoryPolicies(RemoteRepository dominant, RemoteRepository recessive) { - if (dominant instanceof DefaultRemoteRepository d && recessive instanceof DefaultRemoteRepository r) { - org.eclipse.aether.repository.RemoteRepository dr = d.getRepository(); - org.eclipse.aether.repository.RemoteRepository rr = r.getRepository(); - - boolean mergeSnapshots = - rr.getPolicy(true).isEnabled() && !dr.getPolicy(true).isEnabled(); - boolean mergeReleases = - rr.getPolicy(false).isEnabled() && !dr.getPolicy(false).isEnabled(); - - if (mergeSnapshots || mergeReleases) { - org.eclipse.aether.repository.RemoteRepository.Builder builder = - new org.eclipse.aether.repository.RemoteRepository.Builder(dr); - if (mergeSnapshots) { - builder.setSnapshotPolicy(rr.getPolicy(true)); - } - if (mergeReleases) { - builder.setReleasePolicy(rr.getPolicy(false)); - } - return new DefaultRemoteRepository(builder.build()); - } - } - return dominant; + return List.copyOf( + request.getRepositories() != null + ? request.getRepositories() + : request.getSession().getRemoteRepositories()); } @SuppressWarnings("checkstyle:ParameterNumber") @@ -385,25 +316,19 @@ private ModelBuilderSessionState( DefaultModelBuilderResult result, Graph dag, Map> mappedSources, - Set reportedImportWarnings, - Map> reactorProblemCollectors, List pomRepositories, List externalRepositories, List repositories, - Set parentChain, - boolean externalOrigin) { + Set parentChain) { this.session = session; this.request = request; this.result = result; this.dag = dag; this.mappedSources = mappedSources; - this.reportedImportWarnings = reportedImportWarnings; - this.reactorProblemCollectors = reactorProblemCollectors; this.pomRepositories = pomRepositories; this.externalRepositories = externalRepositories; this.repositories = repositories; this.parentChain = parentChain; - this.externalOrigin = externalOrigin; this.result.setSource(this.request.getSource()); } @@ -423,18 +348,6 @@ ModelBuilderSessionState derive(ModelBuilderRequest request) { } ModelBuilderSessionState derive(ModelBuilderRequest request, DefaultModelBuilderResult result) { - return derive(request, result, reportedImportWarnings, reactorProblemCollectors); - } - - ModelBuilderSessionState deriveTopLevel(ModelBuilderRequest request, DefaultModelBuilderResult result) { - return derive(request, result, ConcurrentHashMap.newKeySet(), new ConcurrentHashMap<>()); - } - - private ModelBuilderSessionState derive( - ModelBuilderRequest request, - DefaultModelBuilderResult result, - Set reportedImportWarnings, - Map> reactorProblemCollectors) { if (session != request.getSession()) { throw new IllegalArgumentException("Session mismatch"); } @@ -457,20 +370,16 @@ private ModelBuilderSessionState derive( derivedRepos = repositoryFactory.aggregate(session, pomRepositories, derivedExtRepos, false); } } - boolean derivedExternalOrigin = externalOrigin || isExternalOrigin(request); return new ModelBuilderSessionState( session, request, result, dag, mappedSources, - reportedImportWarnings, - reactorProblemCollectors, pomRepositories, derivedExtRepos, derivedRepos, - new LinkedHashSet<>(), - derivedExternalOrigin); + new LinkedHashSet<>()); } @Override @@ -673,13 +582,7 @@ public void mergeRepositories(Model model, boolean replace) { && (repo.getId() == null || !repo.getId().contains("${"))) .map(session::createRemoteRepository) .toList(); - // Repositories contributed by a model resolved from a repository are merged - // recessively; repositories supplied by the request or session keep precedence. - // Note: the isBuildRequest() guard means any future non-build RequestType will - // also use recessive merging (the else branch). This is intentional — only a - // build request has a well-defined set of session/request repositories that - // should take precedence; dependency and parent resolution do not. - if (replace && isBuildRequest()) { + if (replace) { Set ids = repos.stream().map(RemoteRepository::getId).collect(Collectors.toSet()); repositories = repositories.stream() .filter(r -> !ids.contains(r.getId())) @@ -705,11 +608,9 @@ public void mergeRepositories(Model model, boolean replace) { // // Transform raw model to build pom. - // Infer missing coordinates from models in the reactor + // Infer inner reactor dependencies version // Model transformFileToRaw(Model model) { - Parent newParent = inferParentVersion(model); - List newDeps = null; boolean depsChanged = false; if (!model.getDependencies().isEmpty()) { @@ -725,13 +626,10 @@ Model transformFileToRaw(Model model) { managedDepsChanged = inferDependencies(model, depMgmt.getDependencies(), newManagedDeps); } - if (newParent == null && !depsChanged && !managedDepsChanged) { + if (!depsChanged && !managedDepsChanged) { return model; } Model.Builder builder = Model.newBuilder(model); - if (newParent != null) { - builder.parent(newParent); - } if (depsChanged) { builder.dependencies(newDeps); } @@ -741,37 +639,6 @@ Model transformFileToRaw(Model model) { return builder.build(); } - private Parent inferParentVersion(Model model) { - Parent parent = model.getParent(); - if (parent == null - || parent.getVersion() != null - || parent.getGroupId() == null - || parent.getArtifactId() == null) { - return null; - } - - Model parentModel = getRawModel(model.getPomFile(), parent.getGroupId(), parent.getArtifactId()); - if (parentModel == null) { - return null; - } - - String version = parentModel.getVersion(); - InputLocation versionLocation = parentModel.getLocation("version"); - if (version == null && parentModel.getParent() != null) { - // Parent model inherits its version from its own parent (grandparent). - // versionLocation may be null if the grandparent has no explicit ; - // Builder.location() silently ignores null values, which is safe here. - version = parentModel.getParent().getVersion(); - versionLocation = parentModel.getParent().getLocation("version"); - } - return version != null - ? parent.with() - .version(version) - .location("version", versionLocation) - .build() - : null; - } - /** * Infers the missing version or groupId of the given dependencies by looking them up in the reactor. * Each dependency, either the original one or the inferred one, is added to {@code result}. @@ -861,29 +728,17 @@ private Map getEnhancedProperties(Model model, Path rootDirector properties.put("project.basedir", basedir); properties.put("project.basedir.uri", basedirUri); } - if (rootDirectory != null) { - try { - String root = rootDirectory.toString(); - String rootUri = rootDirectory.toUri().toString(); - properties.put("project.rootDirectory", root); - properties.put("project.rootDirectory.uri", rootUri); - } catch (IllegalStateException e) { - // Root directory not available, continue without it - } + try { + String root = rootDirectory.toString(); + String rootUri = rootDirectory.toUri().toString(); + properties.put("project.rootDirectory", root); + properties.put("project.rootDirectory.uri", rootUri); + } catch (IllegalStateException e) { + // Root directory not available, continue without it } - // Handle root vs non-root project properties with profile activation. - // Use toAbsolutePath().normalize() for robust comparison — rootDirectory from - // session.getRootDirectory() may not be normalized, while model.getProjectDirectory() - // (derived from pomFile.getParent() in PathSource) is always normalized. Without - // consistent normalization, the root model can incorrectly enter this branch and - // trigger infinite recursion through readFileModel() (GH-12598). - Path normalizedRootDir = - rootDirectory != null ? rootDirectory.toAbsolutePath().normalize() : null; - Path normalizedProjectDir = model.getProjectDirectory() != null - ? model.getProjectDirectory().toAbsolutePath().normalize() - : null; - if (!Objects.equals(normalizedRootDir, normalizedProjectDir)) { + // Handle root vs non-root project properties with profile activation + if (!Objects.equals(rootDirectory, model.getProjectDirectory())) { Path rootModelPath = modelProcessor.locateExistingPom(rootDirectory); if (rootModelPath != null) { // Check if the root model path is within the root directory to prevent infinite loops @@ -892,11 +747,8 @@ private Map getEnhancedProperties(Model model, Path rootDirector // Also skip if the root model is already being read in an outer call frame // to prevent StackOverflowError when a project has an internal parent in a // subdirectory with CI-friendly ${revision} and a .mvn/ root marker (GH-12301). - // Use toAbsolutePath().normalize() for the guard check to handle paths - // obtained via different representations (e.g., symlinks, relative segments). if (isParentWithinRootDirectory(rootModelPath, rootDirectory) - && !activeModelReads.contains( - rootModelPath.toAbsolutePath().normalize())) { + && !activeModelReads.contains(rootModelPath.normalize())) { Model rootModel = derive(Sources.buildSource(rootModelPath)).readFileModel(activeModelReads); properties.putAll(getPropertiesWithProfiles(rootModel, properties)); @@ -939,7 +791,7 @@ private Map getPropertiesWithProfiles(Model model, Map./../module/pom${version-discriminator}.xml) before - // resolving it against the filesystem. Model-wide interpolation happens - // later in the build, but module paths must be resolved here, so we - // interpolate just the path against the user, model and system properties. - subproject = interpolator.interpolate( - subproject, - Interpolator.chain( - request.getUserProperties()::get, - activated.getProperties()::get, - request.getSystemProperties()::get)); - subproject = subproject.replace('\\', File.separatorChar).replace('/', File.separatorChar); Path rawSubprojectFile = modelProcessor.locateExistingPom(pomDirectory.resolve(subproject)); @@ -1230,8 +1067,55 @@ Model readParent( Parent parent, DefaultProfileActivationContext profileActivationContext, Set parentChain) { - return readParentFrames( - new ParentResolutionFrame(childModel, parent, profileActivationContext, parentChain, true, false)); + Model parentModel; + + if (parent != null) { + // Check for circular parent resolution using model IDs + String parentId = parent.getGroupId() + ":" + parent.getArtifactId() + ":" + parent.getVersion(); + if (!parentChain.add(parentId)) { + StringBuilder message = new StringBuilder("The parents form a cycle: "); + for (String id : parentChain) { + message.append(id).append(" -> "); + } + message.append(parentId); + + add(Severity.FATAL, Version.BASE, message.toString()); + throw newModelBuilderException(); + } + + try { + parentModel = resolveParent(childModel, parent, profileActivationContext, parentChain); + + if (!"pom".equals(parentModel.getPackaging())) { + add( + Severity.ERROR, + Version.BASE, + "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint(parentModel) + + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"", + parentModel.getLocation("packaging")); + } + result.setParentModel(parentModel); + + // Recursively read the parent's parent + if (parentModel.getParent() != null) { + readParent(parentModel, parentModel.getParent(), profileActivationContext, parentChain); + } + } finally { + // Remove from chain when done processing this parent + parentChain.remove(parentId); + } + } else { + String superModelVersion = childModel.getModelVersion(); + if (superModelVersion == null || !KNOWN_MODEL_VERSIONS.contains(superModelVersion)) { + // Maven 3.x is always using 4.0.0 version to load the supermodel, so + // do the same when loading a dependency. The model validator will also + // check that field later. + superModelVersion = MODEL_VERSION_4_0_0; + } + parentModel = getSuperModel(superModelVersion); + } + + return parentModel; } private Model resolveParent( @@ -1240,11 +1124,22 @@ private Model resolveParent( DefaultProfileActivationContext profileActivationContext, Set parentChain) throws ModelBuilderException { - return readParentFrames( - new ParentResolutionFrame(childModel, parent, profileActivationContext, parentChain, false, false)); + Model parentModel = null; + if (isBuildRequest()) { + parentModel = readParentLocally(childModel, parent, profileActivationContext, parentChain); + } + if (parentModel == null) { + parentModel = resolveAndReadParentExternally(childModel, parent, profileActivationContext, parentChain); + } + return parentModel; } - private ModelSource findLocalParent(Model childModel, Parent parent) { + private Model readParentLocally( + Model childModel, + Parent parent, + DefaultProfileActivationContext profileActivationContext, + Set parentChain) + throws ModelBuilderException { ModelSource candidateSource; boolean isParentOrSimpleMixin = !(parent instanceof Mixin) @@ -1280,85 +1175,109 @@ private ModelSource findLocalParent(Model childModel, Parent parent) { candidateSource = null; } - return candidateSource; - } + if (candidateSource == null) { + return null; + } - private boolean isLocalParentVersion(Model childModel, Parent parent, Model candidateModel) { - String version = getVersion(candidateModel); + // Check for circular parent resolution using source locations (file paths) + // This must be done BEFORE calling derive() to prevent StackOverflowError + String sourceLocation = candidateSource.getLocation(); - if (version != null && parent.getVersion() != null && !version.equals(parent.getVersion())) { - try { - VersionRange parentRange = versionParser.parseVersionRange(parent.getVersion()); - if (!parentRange.contains(versionParser.parseVersion(version))) { - // version skew drop back to resolution from the repository - return false; - } + if (!parentChain.add(sourceLocation)) { + StringBuilder message = new StringBuilder("The parents form a cycle: "); + for (String location : parentChain) { + message.append(location).append(" -> "); + } + message.append(sourceLocation); + + add(Severity.FATAL, Version.BASE, message.toString()); + throw newModelBuilderException(); + } + + try { + ModelBuilderSessionState derived = derive( + request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_CONSUMER + ? ModelBuilderRequest.builder(request) + .requestType(ModelBuilderRequest.RequestType.CONSUMER_PARENT) + .source(candidateSource) + .build() + : ModelBuilderRequest.build(request, candidateSource)); + + // Check GA match BEFORE readAsParentModel() which recursively resolves + // the candidate's parent chain and can trigger false cycle detection (GH-12074). + Model fileModel = derived.readFileModel(); + String fileGroupId = getGroupId(fileModel); + String fileArtifactId = fileModel.getArtifactId(); + + if (parent.getGroupId() != null && (fileGroupId == null || !fileGroupId.equals(parent.getGroupId())) + || parent.getArtifactId() != null + && (fileArtifactId == null || !fileArtifactId.equals(parent.getArtifactId()))) { + mismatchRelativePathAndGA(childModel, parent, fileGroupId, fileArtifactId); + return null; + } + Model candidateModel = derived.readAsParentModel(profileActivationContext, parentChain); + // Add profiles from parent, preserving model ID tracking + for (Map.Entry> entry : + derived.result.getActivePomProfilesByModel().entrySet()) { + addActivePomProfiles(entry.getKey(), entry.getValue()); + } - // Validate versions aren't inherited when using parent ranges the same way as when read - // externally. - String rawChildModelVersion = childModel.getVersion(); + String version = getVersion(candidateModel); - if (rawChildModelVersion == null) { - // Message below is checked for in the MNG-2199 core IT. - add(Severity.FATAL, Version.V31, "Version must be a constant", childModel.getLocation("")); + if (version != null && parent.getVersion() != null && !version.equals(parent.getVersion())) { + try { + VersionRange parentRange = versionParser.parseVersionRange(parent.getVersion()); + if (!parentRange.contains(versionParser.parseVersion(version))) { + // version skew drop back to resolution from the repository + return null; + } + + // Validate versions aren't inherited when using parent ranges the same way as when read + // externally. + String rawChildModelVersion = childModel.getVersion(); - } else { - if (rawChildVersionReferencesParent(rawChildModelVersion)) { + if (rawChildModelVersion == null) { // Message below is checked for in the MNG-2199 core IT. - add( - Severity.FATAL, - Version.V31, - "Version must be a constant", - childModel.getLocation("version")); + add(Severity.FATAL, Version.V31, "Version must be a constant", childModel.getLocation("")); + + } else { + if (rawChildVersionReferencesParent(rawChildModelVersion)) { + // Message below is checked for in the MNG-2199 core IT. + add( + Severity.FATAL, + Version.V31, + "Version must be a constant", + childModel.getLocation("version")); + } } - } - // MNG-2199: What else to check here ? - } catch (VersionParserException e) { - // invalid version range, so drop back to resolution from the repository - return false; + // MNG-2199: What else to check here ? + } catch (VersionParserException e) { + // invalid version range, so drop back to resolution from the repository + return null; + } } + return candidateModel; + } finally { + // Remove the source location from the chain when we're done processing this parent + parentChain.remove(sourceLocation); } - return true; } private void mismatchRelativePathAndGA(Model childModel, Parent parent, String groupId, String artifactId) { - boolean defaultPath = parent.getRelativePath() == null; - boolean maven3Mode = Features.mavenMaven3Personality( - InternalSession.from(session).getSession().getConfigProperties()); - - String actual = groupId + ':' + artifactId; - String declared = parent.getGroupId() + ':' + parent.getArtifactId(); - String sourceHint = (childModel != getRootModel()) ? ModelProblemUtils.toSourceHint(childModel) : null; - - String message; - if (defaultPath) { - // was omitted — Maven probed ../pom.xml on its own - message = "Maven probed the default location '../pom.xml'" - + (sourceHint != null ? " for POM " + sourceHint : "") - + " and found " + actual - + " instead of the declared parent " + declared - + ". Maven will fall back to repository resolution." - + " To suppress this warning, add to your declaration."; - } else { - // was set explicitly — this is a configuration error - message = "'parent.relativePath'" - + (sourceHint != null ? " of POM " + sourceHint : "") - + " points at '" + parent.getRelativePath() + "'" - + " which resolves to " + actual - + " instead of the declared parent " + declared - + (maven3Mode - ? ". Please verify your project structure." - : ". Correct the value or remove it to let Maven resolve the parent" - + " from the repository."); + StringBuilder buffer = new StringBuilder(256); + buffer.append("'parent.relativePath'"); + if (childModel != getRootModel()) { + buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel)); } + buffer.append(" points at ").append(groupId).append(':').append(artifactId); + buffer.append(" instead of ").append(parent.getGroupId()).append(':'); + buffer.append(parent.getArtifactId()).append(", please verify your project structure"); setSource(childModel); - // WARNING when: Maven probed the default path (user didn't set anything), - // OR maven3Personality is active (preserve historical lenient behaviour). - // FATAL otherwise: explicit pointing at the wrong artifact is a config error. - boolean warn = defaultPath || maven3Mode; - add(warn ? Severity.WARNING : Severity.FATAL, Version.BASE, message, parent.getLocation("")); + boolean warn = MODEL_VERSION_4_0_0.equals(childModel.getModelVersion()) + || childModel.getParent().getRelativePath() == null; + add(warn ? Severity.WARNING : Severity.FATAL, Version.BASE, buffer.toString(), parent.getLocation("")); } private void wrongParentRelativePath(Model childModel) { @@ -1382,16 +1301,6 @@ Model resolveAndReadParentExternally( DefaultProfileActivationContext profileActivationContext, Set parentChain) throws ModelBuilderException { - return readParentFrames( - new ParentResolutionFrame(childModel, parent, profileActivationContext, parentChain, false, true)); - } - - private record ResolvedParentKey( - String groupId, String artifactId, String version, String classifier, String extension) {} - - private record ExternalParent(ModelBuilderSessionState state, Parent parent, ResolvedParentKey key) {} - - private ExternalParent resolveExternalParent(Model childModel, Parent parent) { ModelBuilderRequest request = this.request; setSource(childModel); @@ -1406,8 +1315,8 @@ private ExternalParent resolveExternalParent(Model childModel, Parent parent) { var previousRepositories = repositories; mergeRepositories(childModel, false); if (!Objects.equals(previousRepositories, repositories)) { - if (logger.isDebugEnabled()) { - logger.debug("Merging repositories from " + childModel.getId() + "\n" + if (logger.isTraceEnabled()) { + logger.trace("Merging repositories from " + childModel.getId() + "\n" + repositories.stream() .map(Object::toString) .collect(Collectors.joining("\n", " ", ""))); @@ -1460,18 +1369,14 @@ private ExternalParent resolveExternalParent(Model childModel, Parent parent) { .source(modelSource) .build(); - return new ExternalParent( - derive(lenientRequest), - parent, - new ResolvedParentKey( - groupId, - artifactId, - parent.getVersion(), - classifier, - extension != null ? extension : "pom")); - } + ModelBuilderSessionState derived = derive(lenientRequest); + Model parentModel = derived.readAsParentModel(profileActivationContext, parentChain); + // Add profiles from parent, preserving model ID tracking + for (Map.Entry> entry : + derived.result.getActivePomProfilesByModel().entrySet()) { + addActivePomProfiles(entry.getKey(), entry.getValue()); + } - private void validateExternalParentVersion(Model childModel, Parent parent, String version) { if (!parent.getVersion().equals(version)) { String rawChildModelVersion = childModel.getVersion(); @@ -1491,6 +1396,8 @@ private void validateExternalParentVersion(Model childModel, Parent parent, Stri // MNG-2199: What else to check here ? } + + return parentModel; } Model activateFileModel(Model inputModel) throws ModelBuilderException { @@ -1631,7 +1538,7 @@ private Model readEffectiveModel() throws ModelBuilderException { List newRepos = repositories.stream().map(Object::toString).toList(); if (!Objects.equals(oldRepos, newRepos)) { - logger.debug("Replacing repositories from " + resultModel.getId() + "\n" + logger.trace("Replacing repositories from " + resultModel.getId() + "\n" + newRepos.stream().map(s -> " " + s).collect(Collectors.joining("\n"))); } } @@ -1649,103 +1556,10 @@ private void addActivePomProfiles(String modelId, List activePomProfile private List getActiveProfiles( Collection interpolatedProfiles, DefaultProfileActivationContext profileActivationContext) { if (isBuildRequestWithActivation()) { - if (externalOrigin) { - // A model resolved to satisfy dependency resolution -- a dependency POM - // itself, or one of its parents, reached transitively -- evaluates profiles - // against a sandboxed activation context. The sandbox: - // - merges model properties into system property lookups (so POM-declared - // drive activation via the existing property lookup chain), - // - suppresses user properties (consumer -D flags must not activate - // dependency profiles — they were not set for that artifact), - // - disables file existence checks (publisher paths don't exist here). - // Model properties are merged into system properties rather than adding - // a separate lookup step in PropertyProfileActivator, because changing the - // activator would affect ALL profile evaluations (including the build's own - // project) and cause unintended profile activation when a POM declares a - // property that matches a profile's activation condition. - // File-activated profiles are pre-filtered (not just sandboxed) because - // returning false from exists() would incorrectly activate profiles. - // Repository stripping is intentionally omitted: only legitimately-active - // profiles (JDK/OS/activeByDefault and POM-property-gated) reach injection, - // and stripping their repositories would break the established - // project → dep1 → dep2 pattern. See #13100. - // TODO(#13146): repositories contributed by external-model profiles can shadow - // central; a WARN/FAIL policy for URL mismatches should be added separately. - // Condition profiles using exists()/missing() are also pre-filtered for the - // same reason as file profiles: in the sandbox, context.exists() always returns - // false, so missing(path) evaluates to !false = true and fires unconditionally. - Collection nonFileProfiles = interpolatedProfiles.stream() - .filter(p -> p.getActivation() == null - || (p.getActivation().getFile() == null && !hasFileConditionExpression(p))) - .toList(); - ProfileActivationContext externalContext = - profileActivationContext.withoutUserPropertiesAndFilesystem(); - return profileSelector.getActiveProfiles(nonFileProfiles, externalContext, this); - } return profileSelector.getActiveProfiles(interpolatedProfiles, profileActivationContext, this); } else { - // BUILD_CONSUMER: activate only deterministic profiles whose activation is a - // function of the build platform (OS, JDK version, activeByDefault) rather than - // of environment-specific state (file existence, property values, condition - // expressions). This ensures that platform-dependent properties (e.g. - // ${swt.artifactId} from an OS-activated profile) are resolved before the - // coordinate validator runs, while keeping the consumer POM reproducible across - // environments. Repositories from these profiles are stripped — they must not - // leak into the published consumer POM. - // Packaging-activated profiles are also excluded: the consumer POM builder - // handles them separately via inlinePackagingActivatedProfiles(). - // See GH-13004. - Collection deterministicProfiles = interpolatedProfiles.stream() - .filter(profile -> - !hasFileOrPropertyOrConditionActivation(profile) && !hasPackagingActivation(profile)) - .map(profile -> profile.withRepositories(List.of()).withPluginRepositories(List.of())) - .toList(); - return profileSelector.getActiveProfiles(deterministicProfiles, profileActivationContext, this); - } - } - - /** - * Determines whether the given profile's activation depends on file existence, a - * property, or a condition expression, as opposed to being a function of the build - * platform (JDK version, operating system) or {@code activeByDefault}. - *

- * Used for BUILD_CONSUMER model building to keep the consumer POM deterministic. - * For external (dependency/parent/BOM) models, the sandbox context approach is used - * instead — see {@link DefaultProfileActivationContext#withoutUserPropertiesAndFilesystem()}. - */ - private static boolean hasFileOrPropertyOrConditionActivation(Profile profile) { - Activation activation = profile.getActivation(); - return activation != null - && (activation.getFile() != null - || activation.getProperty() != null - || (activation.getCondition() != null - && !activation.getCondition().isBlank())); - } - - /** - * Returns {@code true} if the profile's condition expression calls {@code exists()} or - * {@code missing()}. Such profiles must be pre-filtered out when building external - * (repository-resolved) models: inside the sandbox, {@code context.exists()} always - * returns {@code false}, so {@code missing(path)} evaluates to {@code !false = true} - * and fires unconditionally — the same footgun that file-activated profiles expose. - */ - private static boolean hasFileConditionExpression(Profile profile) { - Activation a = profile.getActivation(); - if (a == null || a.getCondition() == null) { - return false; + return List.of(); } - String c = a.getCondition(); - return c.contains("exists(") || c.contains("missing("); - } - - /** - * Packaging-activated profiles are handled separately by the consumer POM builder's - * {@code inlinePackagingActivatedProfiles()} and must not be activated during - * BUILD_CONSUMER model building to avoid double-merging their contributions. - */ - private static boolean hasPackagingActivation(Profile profile) { - Activation activation = profile.getActivation(); - return activation != null && activation.getPackaging() != null; } Model readFileModel() throws ModelBuilderException { @@ -1766,13 +1580,9 @@ Model doReadFileModel(Set activeModelReads) throws ModelBuilderException { Path rootDirectory; boolean rootDirectoryFromSession = false; setSource(modelSource.getLocation()); - logger.debug("Reading file model from " + modelSource.getLocation()); + logger.trace("Reading file model from " + modelSource.getLocation()); Path sourcePath = modelSource.getPath(); - // Use toAbsolutePath().normalize() for consistent path identity in activeModelReads. - // This must match the normalization used in getEnhancedProperties() guard check - // to prevent StackOverflowError from path representation mismatches (GH-12598). - Path normalizedPath = - sourcePath != null ? sourcePath.toAbsolutePath().normalize() : null; + Path normalizedPath = sourcePath != null ? sourcePath.normalize() : null; boolean trackRead = normalizedPath != null && activeModelReads.add(normalizedPath); try { try { @@ -1911,9 +1721,7 @@ Model doReadFileModel(Set activeModelReads) throws ModelBuilderException { && !MODEL_VERSION_4_0_0.equals(model.getModelVersion()) // and if packaging is POM (we check type, but the session is not yet available, // we would require the project realm if we want to support extensions - && Type.POM.equals(model.getPackaging()) - // and if discovery is not disabled via property - && Features.discoverSubprojects(request.getUserProperties())) { + && Type.POM.equals(model.getPackaging())) { List subprojects = new ArrayList<>(); try (Stream files = Files.list(model.getProjectDirectory())) { for (Path f : files.toList()) { @@ -1984,7 +1792,7 @@ Model doReadFileModel(Set activeModelReads) throws ModelBuilderException { : null) .build(); } catch (ModelBuilderException e) { - logger.debug( + logger.trace( "Could not read root model properties for CI-friendly version interpolation", e); } } @@ -2149,31 +1957,9 @@ private record ParentModelWithProfiles(Model model, List activatedProfi */ Model readAsParentModel(DefaultProfileActivationContext profileActivationContext, Set parentChain) throws ModelBuilderException { - return readParentFrames(new ParentModelFrame(profileActivationContext, parentChain)); - } + Map parentsPerContext = + cache(request.getSource(), PARENT, ConcurrentHashMap::new); - private Map parentModelsPerContext() { - // Partition the cache by externalOrigin so a parent model resolved while building - // the operator's own project never shares an entry with the same source resolved - // while resolving a dependency: the two contexts activate profiles differently (see - // getActiveProfiles below), and the model built for one must not be reused for the - // other, even though both are keyed off the same underlying source. - // - // This partition is a defensive backstop, not the primary guard: cache(source, tag, - // supplier) additionally scopes each entry to the top-level request (see - // getOuterRequest()), which falls back to the request object's own identity once its - // RequestTrace has no further request-typed ancestor. Two independently-built request - // objects therefore land in different buckets regardless of this tag, and never reach - // this collision in practice; the tag matters only when two reads end up sharing a - // request object (as derive() calls from a common ancestor can), which is why it is - // kept even though the getActiveProfiles gate above already decides the correct - // activation for each read on its own. - return cache(request.getSource(), externalOrigin ? PARENT_EXTERNAL : PARENT, ConcurrentHashMap::new); - } - - private Model findCachedParent( - DefaultProfileActivationContext profileActivationContext, - Map parentsPerContext) { for (Map.Entry e : parentsPerContext.entrySet()) { if (e.getKey().matches(profileActivationContext)) { @@ -2192,332 +1978,74 @@ private Model findCachedParent( } } - return null; - } - - // Frames retain the same sessions and activation contexts as recursive calls, but - // return completed models through the deque rather than through the Java stack. - private Model readParentFrames(ParentFrame first) { - ArrayDeque frames = new ArrayDeque<>(); - Set activeSources = new LinkedHashSet<>(); - Set activeParents = new LinkedHashSet<>(); - frames.push(first); - try { - while (!frames.isEmpty()) { - ParentFrame frame = frames.peek(); - ParentFrame next = frame.advance(activeSources, activeParents); - if (next != null) { - frames.push(next); - } else if (frame.complete) { - frames.pop().close(); - if (frames.isEmpty()) { - return frame.value; - } - frames.peek().value = frame.value; - } - } - throw new IllegalStateException("No parent model produced"); - } finally { - while (!frames.isEmpty()) { - frames.pop().close(); - } - } - } - - private abstract class ParentFrame { - Model value; - boolean complete; - - abstract ParentFrame advance(Set activeSources, Set activeParents); - - void finish(Model model) { - value = model; - complete = true; - } - - void close() {} - } - - private enum ParentResolutionPhase { - START, - LOCAL, - EXTERNAL - } - - private class ParentResolutionFrame extends ParentFrame { - private final Model child; - private final Parent parent; - private final DefaultProfileActivationContext context; - private final Set chain; - private final boolean declaredParent; - private final boolean externalOnly; - private ParentResolutionPhase phase = ParentResolutionPhase.START; - private ModelBuilderSessionState derived; - private Parent resolvedParent; - private String parentId; - private String localLocation; - - ParentResolutionFrame( - Model child, - Parent parent, - DefaultProfileActivationContext context, - Set chain, - boolean declaredParent, - boolean externalOnly) { - this.child = child; - this.parent = parent; - this.context = context; - this.chain = chain; - this.declaredParent = declaredParent; - this.externalOnly = externalOnly; - } - - @Override - ParentFrame advance(Set activeSources, Set activeParents) { - if (phase == ParentResolutionPhase.START) { - if (declaredParent && parent == null) { - String version = child.getModelVersion(); - finish(getSuperModel( - version != null && KNOWN_MODEL_VERSIONS.contains(version) - ? version - : MODEL_VERSION_4_0_0)); - return null; - } - if (declaredParent) { - parentId = - enter(parent.getGroupId() + ":" + parent.getArtifactId() + ":" + parent.getVersion()); - } - ModelSource source = !externalOnly && isBuildRequest() ? findLocalParent(child, parent) : null; - if (source != null) { - localLocation = enter(source.getLocation()); - derived = derive( - request.getRequestType() == ModelBuilderRequest.RequestType.BUILD_CONSUMER - ? ModelBuilderRequest.builder(request) - .requestType(ModelBuilderRequest.RequestType.CONSUMER_PARENT) - .source(source) - .build() - : ModelBuilderRequest.build(request, source)); - // Reject a wrong GA before descending into its ancestry (GH-12074). - Model file = derived.readFileModel(); - if ((parent.getGroupId() == null || Objects.equals(parent.getGroupId(), getGroupId(file))) - && (parent.getArtifactId() == null - || Objects.equals(parent.getArtifactId(), file.getArtifactId()))) { - phase = ParentResolutionPhase.LOCAL; - return derived.new ParentModelFrame(context, chain); - } - mismatchRelativePathAndGA(child, parent, getGroupId(file), file.getArtifactId()); - leaveLocal(); - } - return external(); - } - - derived.result - .getActivePomProfilesByModel() - .forEach(ModelBuilderSessionState.this::addActivePomProfiles); - if (phase == ParentResolutionPhase.LOCAL) { - boolean matches; - try { - matches = isLocalParentVersion(child, parent, value); - } finally { - leaveLocal(); - } - if (!matches) { - return external(); - } - } else { - validateExternalParentVersion(child, resolvedParent, parent.getVersion()); - } - if (declaredParent) { - if (!"pom".equals(value.getPackaging())) { - add( - Severity.ERROR, - Version.BASE, - "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint(value) - + ", must be \"pom\" but is \"" + value.getPackaging() + "\"", - value.getLocation("packaging")); - } - result.setParentModel(value); - } - // ParentModelFrame has already assembled all ancestors and removed the parent reference. - finish(value); - return null; - } - - private ParentFrame external() { - ExternalParent external = resolveExternalParent(child, parent); - derived = external.state(); - resolvedParent = external.parent(); - phase = ParentResolutionPhase.EXTERNAL; - return derived.new ParentModelFrame(context, chain, external.key()); - } - - private String enter(String marker) { - if (!chain.add(marker)) { - add( - Severity.FATAL, - Version.BASE, - "The parents form a cycle: " + String.join(" -> ", chain) + " -> " + marker); - throw newModelBuilderException(); - } - return marker; - } + // Cache miss: process the parent model + // CRITICAL: Use a separate recording context to avoid recording intermediate keys + // that aren't essential to the final result. Only replay the final essential keys + // into the parent recording context to maintain clean cache keys and avoid + // over-recording during parent model processing. + DefaultProfileActivationContext ctx = profileActivationContext.start(); + ParentModelWithProfiles modelWithProfiles = doReadAsParentModel(ctx, parentChain); + DefaultProfileActivationContext.Record record = ctx.stop(); + replayRecordIntoContext(record, profileActivationContext); - private void leaveLocal() { - if (localLocation != null) { - chain.remove(localLocation); - localLocation = null; - } - } - - @Override - void close() { - leaveLocal(); - if (parentId != null) { - chain.remove(parentId); - parentId = null; - } - } - } - - private enum ParentModelPhase { - START, - PARENT, - MIXIN, - MERGE_MIXIN + parentsPerContext.put(record, modelWithProfiles); + // Use ModelProblemUtils.toId() to get groupId:artifactId:version format (without packaging) + addActivePomProfiles( + ModelProblemUtils.toId(modelWithProfiles.model()), modelWithProfiles.activatedProfiles()); + return modelWithProfiles.model(); } - private class ParentModelFrame extends ParentFrame { - private final DefaultProfileActivationContext context; - private final Set chain; - private final ResolvedParentKey resolvedParent; - private ParentModelPhase phase = ParentModelPhase.START; - private Map models; - private DefaultProfileActivationContext recording; - private DefaultInheritanceAssembler assembler; - private Model model; - private Iterator mixins; - private Set activeSources; - private Set activeParents; - - ParentModelFrame(DefaultProfileActivationContext context, Set chain) { - this(context, chain, null); - } - - ParentModelFrame( - DefaultProfileActivationContext context, Set chain, ResolvedParentKey resolvedParent) { - this.context = context; - this.chain = chain; - this.resolvedParent = resolvedParent; - } - - @Override - ParentFrame advance(Set activeSources, Set activeParents) { - switch (phase) { - case START -> { - models = parentModelsPerContext(); - Model cached = findCachedParent(context, models); - if (cached != null) { - finish(cached); - } else { - // Mixins resolved externally have no GAV or local-path ancestry marker. - // Keep source identity separate and acquire it only while assembling a cache miss. - ModelSource source = request.getSource(); - if (!activeSources.add(source)) { - add( - Severity.FATAL, - Version.BASE, - "The parents form a cycle: " - + activeSources.stream() - .map(ModelSource::getLocation) - .collect(Collectors.joining(" -> ")) - + " -> " + source.getLocation()); - throw newModelBuilderException(); - } - this.activeSources = activeSources; - // Opaque sources need not implement value equality or have unique display locations. - if (resolvedParent != null) { - if (!activeParents.add(resolvedParent)) { - add( - Severity.FATAL, - Version.BASE, - "The parents form a cycle: " + activeParents + " -> " + resolvedParent); - throw newModelBuilderException(); - } - this.activeParents = activeParents; - } - recording = context.start(); - model = readRawModel(); - phase = ParentModelPhase.PARENT; - return new ParentResolutionFrame(model, model.getParent(), recording, chain, true, false); - } - } - case PARENT -> { - assembler = parentInheritanceAssembler(); - model = assembler.assembleModelInheritance( - model, value, request, ModelBuilderSessionState.this); - mixins = model.getMixins().iterator(); - phase = ParentModelPhase.MIXIN; - } - case MIXIN -> { - if (mixins.hasNext()) { - phase = ParentModelPhase.MERGE_MIXIN; - return new ParentResolutionFrame(model, mixins.next(), recording, chain, false, false); - } - List profiles = getActiveProfiles(model.getProfiles(), recording); - model = profileInjector - .injectProfiles(model, profiles, request, ModelBuilderSessionState.this) - .withProfiles(List.of()) - .withParent(null); - DefaultProfileActivationContext.Record record = recording.stop(); - replayRecordIntoContext(record, context); - models.put(record, new ParentModelWithProfiles(model, profiles)); - addActivePomProfiles(ModelProblemUtils.toId(model), profiles); - finish(model); - } - case MERGE_MIXIN -> { - model = assembler.assembleModelInheritance( - model, value, request, ModelBuilderSessionState.this); - Map properties = new HashMap<>(model.getProperties()); - properties.putAll(value.getProperties()); - model = model.withProperties(properties); - phase = ParentModelPhase.MIXIN; - } - default -> throw new IllegalStateException("Unexpected parent model phase: " + phase); - } - return null; + private ParentModelWithProfiles doReadAsParentModel( + DefaultProfileActivationContext childProfileActivationContext, Set parentChain) + throws ModelBuilderException { + Model raw = readRawModel(); + Model parentData = readParent(raw, raw.getParent(), childProfileActivationContext, parentChain); + DefaultInheritanceAssembler defaultInheritanceAssembler = + new DefaultInheritanceAssembler(new DefaultInheritanceAssembler.InheritanceModelMerger() { + @Override + protected void mergeModel_Modules( + Model.Builder builder, + Model target, + Model source, + boolean sourceDominant, + Map context) {} + + @Override + protected void mergeModel_Subprojects( + Model.Builder builder, + Model target, + Model source, + boolean sourceDominant, + Map context) {} + }); + Model parent = defaultInheritanceAssembler.assembleModelInheritance(raw, parentData, request, this); + for (Mixin mixin : parent.getMixins()) { + Model parentModel = resolveParent(parent, mixin, childProfileActivationContext, parentChain); + // Merge mixin into parent + parent = defaultInheritanceAssembler.assembleModelInheritance(parent, parentModel, request, this); + // Ensure mixin properties override any previously inherited properties + Map mergedProperties = new java.util.HashMap<>(parent.getProperties()); + mergedProperties.putAll(parentModel.getProperties()); + parent = parent.withProperties(mergedProperties); } - @Override - void close() { - if (activeParents != null) { - activeParents.remove(resolvedParent); - activeParents = null; - } - if (activeSources != null) { - activeSources.remove(request.getSource()); - activeSources = null; - } - } - } + // Profile injection SHOULD be performed on parent models to ensure + // that profile content becomes part of the parent model before inheritance. + // This ensures proper precedence: child elements override parent elements, + // including elements that came from parent profiles. + // + // Use the child's activation context (passed as parameter) to determine + // which parent profiles should be active, ensuring consistency. + List parentActivePomProfiles = + getActiveProfiles(parent.getProfiles(), childProfileActivationContext); - private DefaultInheritanceAssembler parentInheritanceAssembler() { - return new DefaultInheritanceAssembler(new DefaultInheritanceAssembler.InheritanceModelMerger() { - @Override - protected void mergeModel_Modules( - Model.Builder builder, - Model target, - Model source, - boolean sourceDominant, - Map context) {} + // Inject profiles into parent model + Model injectedParentModel = profileInjector + .injectProfiles(parent, parentActivePomProfiles, request, this) + .withProfiles(List.of()); // Remove profiles after injection to avoid double-processing - @Override - protected void mergeModel_Subprojects( - Model.Builder builder, - Model target, - Model source, - boolean sourceDominant, - Map context) {} - }); + // Note: addActivePomProfiles() will be called by the caller for cache miss case + return new ParentModelWithProfiles(injectedParentModel.withParent(null), parentActivePomProfiles); } private Model importDependencyManagement(Model model, Collection importIds) { @@ -2537,8 +2065,8 @@ private Model importDependencyManagement(Model model, Collection importI for (Iterator it = deps.iterator(); it.hasNext(); ) { Dependency dependency = it.next(); - if (!(("pom".equals(dependency.getType()) && "import".equals(dependency.getScope())) - || "bom".equals(dependency.getType()))) { + if (!("pom".equals(dependency.getType()) && "import".equals(dependency.getScope())) + || "bom".equals(dependency.getType())) { continue; } @@ -2560,112 +2088,7 @@ private Model importDependencyManagement(Model model, Collection importI model = model.withDependencyManagement( model.getDependencyManagement().withDependencies(deps)); - return dependencyManagementImporter.importManagement( - model, importMgmts, request, deduplicatingImportProblemCollector()); - } - - private ModelProblemCollector deduplicatingImportProblemCollector() { - return new DeduplicatingImportProblemCollector(); - } - - /** - * A {@link ModelProblemCollector} wrapper that deduplicates BOM import conflict warnings - * within a single top-level build. When a warning originates from a reactor module, - * it is routed to that module's own problem collector so the warning appears next to the - * declaration rather than being repeated for every inheriting child. Non-warning problems - * and warnings without a resolvable source are forwarded to the enclosing - * {@link ModelBuilderSessionState} unchanged. - */ - private class DeduplicatingImportProblemCollector implements ModelProblemCollector { - @Override - public ProblemCollector getProblemCollector() { - return ModelBuilderSessionState.this.getProblemCollector(); - } - - @Override - public void add( - BuilderProblem.Severity severity, - ModelProblem.Version version, - String message, - InputLocation location, - Exception exception) { - if (severity == Severity.WARNING && location != null && location.getSource() != null) { - var source = location.getSource(); - String sourceLocation = source.getLocation(); - ImportWarningKey key = new ImportWarningKey( - message, - sourceLocation, - source.getModelId(), - location.getLineNumber(), - location.getColumnNumber()); - if (!reportedImportWarnings.add(key)) { - return; - } - ProblemCollector collector = - sourceLocation != null ? reactorProblemCollectors.get(sourceLocation) : null; - if (collector != null) { - collector.reportProblem(new DefaultModelProblem( - message, - severity, - version, - sourceLocation, - location.getLineNumber(), - location.getColumnNumber(), - source.getModelId(), - exception)); - return; - } - } - ModelBuilderSessionState.this.add(severity, version, message, location, exception); - } - - @Override - public ModelBuilderException newModelBuilderException() { - return ModelBuilderSessionState.this.newModelBuilderException(); - } - - @Override - public void setSource(String location) { - ModelBuilderSessionState.this.setSource(location); - } - - @Override - public void setSource(Model model) { - ModelBuilderSessionState.this.setSource(model); - } - - @Override - public String getSource() { - return ModelBuilderSessionState.this.getSource(); - } - - @Override - public void setRootModel(Model model) { - ModelBuilderSessionState.this.setRootModel(model); - } - - @Override - public Model getRootModel() { - return ModelBuilderSessionState.this.getRootModel(); - } - } - - /** - * Registers the problem collector under both the location string (path form) and - * the URI form of the source. Import warnings produced by - * {@link DefaultDependencyManagementImporter} carry whichever form the resolver - * happened to record, so both keys are registered as a safety net to ensure a - * lookup in {@link DeduplicatingImportProblemCollector#add} always finds the - * declaring model's collector. - */ - private void registerReactorProblemCollector( - ModelSource source, ProblemCollector problemCollector) { - if (source.getLocation() != null) { - reactorProblemCollectors.put(source.getLocation(), problemCollector); - } - if (source.getPath() != null) { - reactorProblemCollectors.put(source.getPath().toUri().toString(), problemCollector); - } + return dependencyManagementImporter.importManagement(model, importMgmts, request, this); } private DependencyManagement loadDependencyManagement(Dependency dependency, Collection importIds) { @@ -2738,9 +2161,7 @@ private DependencyManagement loadDependencyManagement(Dependency dependency, Col importMgmt = importMgmt.withDependencies(dependencies); } - return DependencyManagement.newBuilder(importMgmt, true) - .importedFrom(dependency.getLocation("")) - .build(); + return importMgmt; } @SuppressWarnings("checkstyle:parameternumber") @@ -2752,13 +2173,11 @@ private Model doLoadDependencyManagement( Collection importIds) { Model importModel; ModelSource importSource; - boolean repositoryResolved = false; try { importSource = resolveReactorModel(groupId, artifactId, version); if (importSource == null) { importSource = modelResolver.resolveModel( request.getSession(), repositories, dependency, new AtomicReference<>()); - repositoryResolved = true; } } catch (ModelBuilderException | ModelResolverException e) { StringBuilder buffer = new StringBuilder(256); @@ -2809,68 +2228,9 @@ private Model doLoadDependencyManagement( importModel = importResult.getEffectiveModel(); - if (repositoryResolved) { - importModel = rejectSystemScopeFromRepositoryImport(importModel, dependency); - } - return importModel; } - /** - * Dependency management imported (as a BOM) from a POM resolved from a repository, rather - * than from the local reactor, may not declare {@code system} scope or a - * {@code systemPath} for a managed dependency: by default, offending entries are dropped - * from the imported management (so a cached import cannot re-introduce them) and a - * warning is emitted, unless the - * {@code maven.repository.dependencyManagement.allowSystemScope} user property is set to - * {@code true}, in which case they are imported as before, with a warning. Dependency - * management imported from the local reactor is not affected. - */ - private Model rejectSystemScopeFromRepositoryImport(Model importModel, Dependency dependency) { - DependencyManagement importMgmt = importModel != null ? importModel.getDependencyManagement() : null; - if (importMgmt == null) { - return importModel; - } - String offending = importMgmt.getDependencies().stream() - .filter(DefaultModelBuilder::usesSystemScope) - .map(Dependency::getManagementKey) - .collect(Collectors.joining(", ")); - if (offending.isEmpty()) { - return importModel; - } - String allow = request.getUserProperties() - .getOrDefault( - Constants.MAVEN_REPOSITORY_DEPENDENCY_MANAGEMENT_ALLOW_SYSTEM_SCOPE, - request.getSystemProperties() - .get(Constants.MAVEN_REPOSITORY_DEPENDENCY_MANAGEMENT_ALLOW_SYSTEM_SCOPE)); - if (Boolean.parseBoolean(allow)) { - add( - Severity.WARNING, - Version.V41, - "The import POM " + ModelProblemUtils.toId(importModel) - + " declares 'system' scope or 'systemPath' for " + offending - + "; importing it because the '" - + Constants.MAVEN_REPOSITORY_DEPENDENCY_MANAGEMENT_ALLOW_SYSTEM_SCOPE - + "' user property is set to 'true'.", - dependency.getLocation("")); - return importModel; - } - add( - Severity.WARNING, - Version.V41, - "The import POM " + ModelProblemUtils.toId(importModel) - + " was resolved from a repository and declares 'system' scope or 'systemPath' for " - + offending + "; these entries are not imported. Remove the 'system' scope from the" - + " imported POM, or set the '" - + Constants.MAVEN_REPOSITORY_DEPENDENCY_MANAGEMENT_ALLOW_SYSTEM_SCOPE - + "' user property to 'true' to import them as before.", - dependency.getLocation("")); - List retained = importMgmt.getDependencies().stream() - .filter(d -> !usesSystemScope(d)) - .collect(Collectors.toList()); - return importModel.withDependencyManagement(importMgmt.withDependencies(retained)); - } - ModelSource resolveReactorModel(String groupId, String artifactId, String version) throws ModelBuilderException { Set sources = mappedSources.get(new GAKey(groupId, artifactId)); @@ -2976,16 +2336,17 @@ private static List getSubprojects(Model activated) { } /** - * Checks whether the model has a non-empty {@code } or {@code } element. - *

- * When this returns {@code false} and auto-discovery is enabled (via - * {@link Features#discoverSubprojects(Map)}), Maven will scan subdirectories - * for POM files. Users who want to suppress discovery without listing subprojects - * can set {@code -Dmaven.project.discoverSubprojects=false}. + * Checks if subprojects are explicitly defined in the main model. + * This method distinguishes between: + * 1. No subprojects/modules element present - returns false (should auto-discover) + * 2. Empty subprojects/modules element present - returns true (should NOT auto-discover) + * 3. Non-empty subprojects/modules - returns true (should NOT auto-discover) */ @SuppressWarnings("deprecation") private static boolean hasSubprojectsDefined(Model model) { - return !model.getSubprojects().isEmpty() || !model.getModules().isEmpty(); + // Only consider the main model: profiles do not influence auto-discovery + // Inline the check for explicit elements using location tracking + return model.getLocation("subprojects") != null || model.getLocation("modules") != null; } @Override @@ -3004,7 +2365,7 @@ public Model buildRawModel(ModelBuilderRequest request) throws ModelBuilderExcep clearRequestScopedCache(request); } catch (Exception e) { // Log but don't fail the build due to cache cleanup issues - logger.debug("Failed to clear REQUEST_SCOPED cache for raw model request: {}", request, e); + logger.trace("Failed to clear REQUEST_SCOPED cache for raw model request: {}", request, e); } RequestTraceHelper.exit(trace); } @@ -3026,26 +2387,9 @@ static String getVersion(Model model) { return version; } - /** - * Whether the model this request builds was resolved from a repository rather than supplied to - * Maven. {@link org.apache.maven.api.services.Sources#resolvedSource} carries the resolved - * model's coordinates and is the only source kind that does; a POM built from a file the caller - * pointed at reports none. - */ - static boolean isExternalOrigin(ModelBuilderRequest request) { - return request.getRequestType() == ModelBuilderRequest.RequestType.CONSUMER_DEPENDENCY - && request.getSource() != null - && request.getSource().getModelId() != null; - } - - static boolean usesSystemScope(Dependency dependency) { - return "system".equals(dependency.getScope()) - || (dependency.getSystemPath() != null - && !dependency.getSystemPath().isEmpty()); - } - private DefaultProfileActivationContext getProfileActivationContext(ModelBuilderRequest request, Model model) { return new DefaultProfileActivationContext( + pathTranslator, rootLocator, interpolator, request.getActiveProfileIds(), @@ -3137,14 +2481,6 @@ private boolean containsCoordinates(String message, String groupId, String artif record GAKey(String groupId, String artifactId) {} - /** - * Composite key used to deduplicate BOM import conflict warnings within a single top-level build. - * Two warnings are considered duplicates when they share the same message text and originate - * from the same source location (file, model ID, line, and column). - */ - private record ImportWarningKey( - String message, String sourceLocation, String sourceModelId, int lineNumber, int columnNumber) {} - public record RgavCacheKey( Session session, RequestTrace trace, @@ -3379,8 +2715,8 @@ private > void clearRequestScopedCache(REQ req) { int beforeSize = map.size(); map.removeIf((k, v) -> !(k instanceof RgavCacheKey) && !(k instanceof SourceCacheKey)); int afterSize = map.size(); - if (logger.isDebugEnabled()) { - logger.debug( + if (logger.isTraceEnabled()) { + logger.trace( "Cleared REQUEST_SCOPED cache for request: {}, removed {} entries, remaining entries: {}", outerRequestKey.getClass().getSimpleName(), afterSize - beforeSize, @@ -3447,4 +2783,4 @@ private static boolean isParentWithinRootDirectory(Path parentPath, Path rootDir return true; } } -} +} \ No newline at end of file diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java index 4283cfceaec2..dfab6b336b7f 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java @@ -352,7 +352,7 @@ private void populateResult(InternalSession session, ArtifactDescriptorResult re for (org.apache.maven.api.model.Dependency dependency : model.getDependencies()) { if (hasUninterpolatedExpression(dependency)) { - logger.debug("Filtered dependency with uninterpolated expression: {}", dependency); + logger.trace("Filtered dependency with uninterpolated expression: {}", dependency); continue; } result.addDependency(convert(dependency, stereotypes)); @@ -362,7 +362,7 @@ private void populateResult(InternalSession session, ArtifactDescriptorResult re if (dependencyManagement != null) { for (org.apache.maven.api.model.Dependency dependency : dependencyManagement.getDependencies()) { if (hasUninterpolatedExpression(dependency)) { - logger.debug("Filtered managed dependency with uninterpolated expression: {}", dependency); + logger.trace("Filtered managed dependency with uninterpolated expression: {}", dependency); continue; } result.addManagedDependency(convert(dependency, stereotypes)); @@ -440,21 +440,21 @@ private static boolean hasUninterpolatedExpression(org.apache.maven.api.model.De private void filterUninterpolated(ArtifactDescriptorResult result) { result.getRepositories().removeIf(repo -> { if (containsPlaceholder(repo.getId()) || containsPlaceholder(repo.getUrl())) { - logger.debug("Filtered repository with uninterpolated expression: {}", repo); + logger.trace("Filtered repository with uninterpolated expression: {}", repo); return true; } return false; }); result.getDependencies().removeIf(dep -> { if (hasUninterpolatedExpression(dep.getArtifact())) { - logger.debug("Filtered dependency with uninterpolated expression: {}", dep); + logger.trace("Filtered dependency with uninterpolated expression: {}", dep); return true; } return false; }); result.getManagedDependencies().removeIf(dep -> { if (hasUninterpolatedExpression(dep.getArtifact())) { - logger.debug("Filtered managed dependency with uninterpolated expression: {}", dep); + logger.trace("Filtered managed dependency with uninterpolated expression: {}", dep); return true; } return false; @@ -483,4 +483,4 @@ private void setArtifactProperties(ArtifactDescriptorResult result, Model model) } } } -} +} \ No newline at end of file diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/relocation/DistributionManagementArtifactRelocationSource.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/relocation/DistributionManagementArtifactRelocationSource.java index c912ece00e64..a001243379af 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/relocation/DistributionManagementArtifactRelocationSource.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/relocation/DistributionManagementArtifactRelocationSource.java @@ -25,11 +25,9 @@ import org.apache.maven.api.model.Model; import org.apache.maven.api.model.Relocation; import org.apache.maven.impl.resolver.MavenArtifactRelocationSource; -import org.apache.maven.impl.resolver.MetadataInputValidator; import org.apache.maven.impl.resolver.RelocatedArtifact; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.resolution.ArtifactDescriptorException; import org.eclipse.aether.resolution.ArtifactDescriptorResult; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,48 +49,27 @@ public final class DistributionManagementArtifactRelocationSource implements Mav @Override public Artifact relocatedTarget( - RepositorySystemSession session, ArtifactDescriptorResult artifactDescriptorResult, Model model) - throws ArtifactDescriptorException { + RepositorySystemSession session, ArtifactDescriptorResult artifactDescriptorResult, Model model) { DistributionManagement distMgmt = model.getDistributionManagement(); if (distMgmt != null) { Relocation relocation = distMgmt.getRelocation(); if (relocation != null) { - Artifact original = artifactDescriptorResult.getRequest().getArtifact(); - validateCoordinateComponent(relocation.getGroupId(), "groupId", artifactDescriptorResult); - validateCoordinateComponent(relocation.getArtifactId(), "artifactId", artifactDescriptorResult); - validateCoordinateComponent(relocation.getVersion(), "version", artifactDescriptorResult); Artifact result = new RelocatedArtifact( - original, + artifactDescriptorResult.getRequest().getArtifact(), relocation.getGroupId(), relocation.getArtifactId(), null, null, relocation.getVersion(), relocation.getMessage()); - LOGGER.debug("The artifact {} has been relocated to {}: {}", original, result, relocation.getMessage()); + LOGGER.trace( + "The artifact {} has been relocated to {}: {}", + artifactDescriptorResult.getRequest().getArtifact(), + result, + relocation.getMessage()); return result; } } return null; } - - /** - * Checks that a relocation coordinate component is usable as an artifact coordinate. Components outside - * the coordinate character set are rejected so that only well-formed coordinates enter resolution. - */ - private static void validateCoordinateComponent( - String value, String component, ArtifactDescriptorResult artifactDescriptorResult) - throws ArtifactDescriptorException { - if (value == null || value.isEmpty()) { - return; // component is not relocated: the original artifact's value is kept - } - if (MetadataInputValidator.isInvalidCoordinateComponent(value)) { - IllegalArgumentException cause = new IllegalArgumentException("Invalid relocation " + component + " '" - + value + "' in artifact descriptor for " - + artifactDescriptorResult.getRequest().getArtifact() - + ": not a valid artifact coordinate component"); - artifactDescriptorResult.addException(cause); - throw new ArtifactDescriptorException(artifactDescriptorResult, cause.getMessage(), cause); - } - } -} +} \ No newline at end of file diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/relocation/UserPropertiesArtifactRelocationSource.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/relocation/UserPropertiesArtifactRelocationSource.java index a667b2a2864d..410756bba789 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/relocation/UserPropertiesArtifactRelocationSource.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/relocation/UserPropertiesArtifactRelocationSource.java @@ -69,7 +69,7 @@ public Artifact relocatedTarget( if (relocation.target == SENTINEL) { String message = "The artifact " + original + " has been banned from resolution: " + (relocation.global ? "User global ban" : "User project ban"); - LOGGER.debug(message); + LOGGER.trace(message); throw new ArtifactDescriptorException(artifactDescriptorResult, message); } Artifact result = new RelocatedArtifact( @@ -80,7 +80,7 @@ public Artifact relocatedTarget( isAny(relocation.target.getExtension()) ? null : relocation.target.getExtension(), isAny(relocation.target.getVersion()) ? null : relocation.target.getVersion(), relocation.global ? "User global relocation" : "User project relocation"); - LOGGER.debug( + LOGGER.trace( "The artifact {} has been relocated to {}: {}", original, result, @@ -204,4 +204,4 @@ private static Artifact parseArtifact(String coords) { }; return s; } -} +} \ No newline at end of file diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/TypeDeriver.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/TypeDeriver.java index 6343cd2cbfa7..a2e47f51a987 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/TypeDeriver.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/type/TypeDeriver.java @@ -60,13 +60,13 @@ public class TypeDeriver implements DependencyGraphTransformer { @Override public DependencyNode transformGraph(DependencyNode root, DependencyGraphTransformationContext context) { ArtifactTypeRegistry registry = context.getSession().getArtifactTypeRegistry(); - if (logger.isDebugEnabled()) { + if (logger.isTraceEnabled()) { StringBuilder sb = new StringBuilder(); root.accept(new DependencyGraphDumper( l -> sb.append(l).append("\n"), DependencyGraphDumper.defaultsWith( List.of(DependencyGraphDumper.artifactProperties(List.of(ArtifactProperties.TYPE)))))); - logger.debug("TYPES: Before transform:\n {}", sb); + logger.trace("TYPES: Before transform:\n {}", sb); } root.accept(new TypeDeriverVisitor(registry)); // Apply processor type info collected by TypeCollector before conflict resolution. @@ -78,13 +78,13 @@ public DependencyNode transformGraph(DependencyNode root, DependencyGraphTransfo if (collectedProcessorTypes != null) { root.accept(new ProcessorTypeMerger(collectedProcessorTypes)); } - if (logger.isDebugEnabled()) { + if (logger.isTraceEnabled()) { StringBuilder sb = new StringBuilder(); root.accept(new DependencyGraphDumper( l -> sb.append(l).append("\n"), DependencyGraphDumper.defaultsWith( List.of(DependencyGraphDumper.artifactProperties(List.of(ArtifactProperties.TYPE)))))); - logger.debug("TYPES: After transform:\n {}", sb); + logger.trace("TYPES: After transform:\n {}", sb); } return root; } @@ -200,4 +200,4 @@ public boolean visitLeave(DependencyNode node) { return true; } } -} +} \ No newline at end of file