You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@maven.apache.org by "elharo (via GitHub)" <gi...@apache.org> on 2026/07/26 12:32:16 UTC

[PR] Fix MWAR-220: filter overlay jars conflicting with managed dependencies [maven-war-plugin]

elharo opened a new pull request, #639:
URL: https://github.com/apache/maven-war-plugin/pull/639

   ## Fix for MWAR-220 / issue #389
   
   When a project uses dependencyManagement to pin a specific version of a library, any jar in a WAR overlay's `WEB-INF/lib` with the same artifactId but a different version will now be removed during overlay processing.
   
   ### How it works
   In `OverlayPackagingTask.performPackaging()`, after unpacking the overlay and before copying files, the new `filterConflictingDependencyJars()` method scans the overlay's `WEB-INF/lib` directory. For each jar, it extracts the artifactId from the filename (following the `artifactId-version(-classifier)?.jar` convention). If the artifactId matches a non-optional jar artifact from the project's dependency tree, the overlay jar is removed — the managed version will be provided by the project's own dependency resolution.
   
   ### Additional changes
   - Updated the MWAR-389 IT test (`verify.bsh`) to remove print statements for the passing case per review feedback.
   
   The IT test in PR #638 documents this issue and now passes with this fix applied.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [MWAR-220] filter overlay jars conflicting with managed dependencies [maven-war-plugin]

Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #639:
URL: https://github.com/apache/maven-war-plugin/pull/639#discussion_r3653185691


##########
src/main/java/org/apache/maven/plugins/war/packaging/OverlayPackagingTask.java:
##########
@@ -127,4 +134,76 @@ protected File getOverlayTempDirectory(WarPackagingContext context, Overlay over
         }
         return result;
     }
+
+    /**
+     * Removes jars from the overlay's {@code WEB-INF/lib} that conflict with the project's managed
+     * dependencies. When a project uses dependencyManagement to pin a version, any jar from the
+     * overlay with the same artifactId but a different version is removed, ensuring only the
+     * dependency-managed version ends up in {@code WEB-INF/lib}.
+     *

Review Comment:
   The JavaDoc states that only overlay JARs with the same artifactId but a *different version* are removed and that this is specifically about dependencyManagement. The implementation currently removes any overlay JAR whose artifactId matches a resolved runtime project dependency, regardless of version and regardless of whether it was managed. Either align the implementation with the JavaDoc/PR description, or adjust the JavaDoc to reflect what the code actually does.
   
   This issue also appears on line 174 of the same file.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [MWAR-220] filter overlay jars conflicting with managed dependencies [maven-war-plugin]

Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #639:
URL: https://github.com/apache/maven-war-plugin/pull/639#discussion_r3665665260


##########
src/main/java/org/apache/maven/plugins/war/packaging/OverlayPackagingTask.java:
##########
@@ -127,4 +142,136 @@ protected File getOverlayTempDirectory(WarPackagingContext context, Overlay over
         }
         return result;
     }
+
+    /**
+     * Identifies jars from the overlay's {@code WEB-INF/lib} whose groupId:artifactId matches a
+     * non-optional runtime-scope dependency resolved by the project. When the overlay jar contains
+     * {@code META-INF/maven/**\/pom.properties}, the groupId is read from that metadata for a precise
+     * match. Otherwise, matching falls back to artifactId only.
+     *
+     * <p>The overlay's cached unpack directory is <em>not</em> mutated; the returned set is used
+     * as additional excludes during the copy step.
+     *
+     * @param context the packaging context
+     * @param overlayDir the unpacked overlay directory
+     * @return set of paths (relative to the overlay dir) to exclude from the overlay copy
+     */
+    private Set<String> computeConflictingJars(WarPackagingContext context, File overlayDir) {
+        File libDir = new File(overlayDir, "WEB-INF/lib");
+        if (!libDir.isDirectory()) {
+            return Collections.emptySet();
+        }
+
+        ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME);
+        Set<String> projectArtifactKeys = new HashSet<>();
+        Set<String> projectFallbackIds = new HashSet<>();
+        for (Artifact artifact : context.getProject().getArtifacts()) {
+            if (!artifact.isOptional() && filter.include(artifact) && "jar".equals(artifact.getType())) {
+                projectArtifactKeys.add(artifact.getGroupId() + ":" + artifact.getArtifactId());
+                projectFallbackIds.add(artifact.getArtifactId());
+            }
+        }
+
+        if (projectArtifactKeys.isEmpty()) {
+            return Collections.emptySet();
+        }
+
+        File[] overlayJars = libDir.listFiles((dir, name) -> name.endsWith(".jar"));
+        if (overlayJars == null) {
+            return Collections.emptySet();
+        }
+
+        Set<String> conflicting = new HashSet<>();
+        for (File overlayJar : overlayJars) {
+            String jarName = overlayJar.getName();
+            String artifactId = extractArtifactId(jarName);
+            if (artifactId == null) {
+                continue;
+            }
+
+            String groupId = getJarGroupId(overlayJar);
+            String key = (groupId != null) ? groupId + ":" + artifactId : artifactId;
+            if ((groupId != null && projectArtifactKeys.contains(key))
+                    || (groupId == null && projectFallbackIds.contains(artifactId))) {
+                context.getLog()
+                        .debug("Excluding dependency [" + jarName + "] from overlay [" + overlay.getId()
+                                + "]; project runtime dependencies already include a version");
+                conflicting.add("WEB-INF/lib/" + jarName);
+            }

Review Comment:
   `computeConflictingJars(...)` references `overlay.getId()` but `overlay` is not in scope in this method, so this will not compile. Pass the `Overlay overlay` into `computeConflictingJars(...)` (and update the call site), or remove the overlay id from the log message and rely on other available context.



##########
src/main/java/org/apache/maven/plugins/war/packaging/OverlayPackagingTask.java:
##########
@@ -127,4 +142,136 @@ protected File getOverlayTempDirectory(WarPackagingContext context, Overlay over
         }
         return result;
     }
+
+    /**
+     * Identifies jars from the overlay's {@code WEB-INF/lib} whose groupId:artifactId matches a
+     * non-optional runtime-scope dependency resolved by the project. When the overlay jar contains
+     * {@code META-INF/maven/**\/pom.properties}, the groupId is read from that metadata for a precise
+     * match. Otherwise, matching falls back to artifactId only.
+     *
+     * <p>The overlay's cached unpack directory is <em>not</em> mutated; the returned set is used
+     * as additional excludes during the copy step.
+     *
+     * @param context the packaging context
+     * @param overlayDir the unpacked overlay directory
+     * @return set of paths (relative to the overlay dir) to exclude from the overlay copy
+     */
+    private Set<String> computeConflictingJars(WarPackagingContext context, File overlayDir) {
+        File libDir = new File(overlayDir, "WEB-INF/lib");
+        if (!libDir.isDirectory()) {
+            return Collections.emptySet();
+        }

Review Comment:
   `computeConflictingJars(...)` references `overlay.getId()` but `overlay` is not in scope in this method, so this will not compile. Pass the `Overlay overlay` into `computeConflictingJars(...)` (and update the call site), or remove the overlay id from the log message and rely on other available context.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [MWAR-220] filter overlay jars conflicting with managed dependencies [maven-war-plugin]

Posted by "elharo (via GitHub)" <gi...@apache.org>.
elharo commented on code in PR #639:
URL: https://github.com/apache/maven-war-plugin/pull/639#discussion_r3652619881


##########
src/it/MWAR-389/verify.bsh:
##########
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.*;
+import java.util.*;
+import org.codehaus.plexus.util.*;
+
+/*
+ * Test for MWAR-220 / issue #389:
+ * dependencyManagement with overlays should not result in multiple versions
+ * of the same dependency in WEB-INF/lib.
+ *
+ * The overlay-war is built with plexus-utils 3.0.24.
+ * The main-war has dependencyManagement pinning plexus-utils to the managed
+ * version (@plexusUtilVersion@), and uses overlay-war as an overlay.
+ *
+ * If the issue still exists, both versions will appear in main-war's WEB-INF/lib.
+ * If fixed, only the managed version will appear.
+ */
+
+String managedVersion = plexusUtilVersion;
+
+// --- Check overlay WAR content ---
+File overlayTarget = new File( basedir, "overlay-war/target" );
+File overlayWar = new File( overlayTarget, "overlay-war-1.0-SNAPSHOT" );
+File overlayLib = new File( overlayWar, "WEB-INF/lib" );
+
+String[] overlayJars = overlayLib.list();
+boolean overlayHasOld = false;
+boolean overlayHasManaged = false;
+
+for ( int i = 0; i < overlayJars.length; i++ )
+{
+    String jar = overlayJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        overlayHasOld = true;
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        overlayHasManaged = true;
+    }
+}
+
+if ( !overlayHasOld )
+{
+    System.err.println( "Overlay WAR missing plexus-utils-3.0.24.jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( overlayHasManaged )
+{
+    System.err.println( "Overlay WAR unexpectedly contains plexus-utils-" + managedVersion + ".jar. "
+        + "Overlay should only have version 3.0.24." );
+    return false;
+}
+
+System.out.println( "Overlay WAR correctly contains only plexus-utils-3.0.24.jar." );
+
+// --- Check main WAR content ---
+File mainTarget = new File( basedir, "main-war/target" );
+File mainWar = new File( mainTarget, "main-war-1.0-SNAPSHOT" );
+File mainLib = new File( mainWar, "WEB-INF/lib" );
+
+String[] mainJars = mainLib.list();
+boolean mainHasOld = false;
+boolean mainHasManaged = false;
+List duplicateGavs = new ArrayList();
+
+for ( int i = 0; i < mainJars.length; i++ )
+{
+    String jar = mainJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        mainHasOld = true;
+        duplicateGavs.add( "plexus-utils:3.0.24 (" + jar + ")" );
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        mainHasManaged = true;
+        duplicateGavs.add( "plexus-utils:" + managedVersion + " (" + jar + ")" );
+    }
+}
+
+if ( !mainHasManaged )
+{
+    System.err.println( "Main WAR missing plexus-utils-" + managedVersion + ".jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( mainHasOld )
+{
+    // Both versions found -- issue STILL EXISTS
+    System.out.println( "ISSUE #389 (MWAR-220) STILL EXISTS:" );
+    System.out.println( "  Both plexus-utils versions found in main WAR WEB-INF/lib:" );
+    System.out.println( "    - plexus-utils-3.0.24.jar (from overlay unpacking)" );

Review Comment:
   remove this; passing tests generate no output



##########
src/it/MWAR-389/verify.bsh:
##########
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.*;
+import java.util.*;
+import org.codehaus.plexus.util.*;
+
+/*
+ * Test for MWAR-220 / issue #389:
+ * dependencyManagement with overlays should not result in multiple versions
+ * of the same dependency in WEB-INF/lib.
+ *
+ * The overlay-war is built with plexus-utils 3.0.24.
+ * The main-war has dependencyManagement pinning plexus-utils to the managed
+ * version (@plexusUtilVersion@), and uses overlay-war as an overlay.
+ *
+ * If the issue still exists, both versions will appear in main-war's WEB-INF/lib.
+ * If fixed, only the managed version will appear.
+ */
+
+String managedVersion = plexusUtilVersion;
+
+// --- Check overlay WAR content ---
+File overlayTarget = new File( basedir, "overlay-war/target" );
+File overlayWar = new File( overlayTarget, "overlay-war-1.0-SNAPSHOT" );
+File overlayLib = new File( overlayWar, "WEB-INF/lib" );
+
+String[] overlayJars = overlayLib.list();
+boolean overlayHasOld = false;
+boolean overlayHasManaged = false;
+
+for ( int i = 0; i < overlayJars.length; i++ )
+{
+    String jar = overlayJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        overlayHasOld = true;
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        overlayHasManaged = true;
+    }
+}
+
+if ( !overlayHasOld )
+{
+    System.err.println( "Overlay WAR missing plexus-utils-3.0.24.jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( overlayHasManaged )
+{
+    System.err.println( "Overlay WAR unexpectedly contains plexus-utils-" + managedVersion + ".jar. "
+        + "Overlay should only have version 3.0.24." );
+    return false;
+}
+
+System.out.println( "Overlay WAR correctly contains only plexus-utils-3.0.24.jar." );

Review Comment:
   remove this; passing tests generate no output



##########
src/it/MWAR-389/verify.bsh:
##########
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.*;
+import java.util.*;
+import org.codehaus.plexus.util.*;
+
+/*
+ * Test for MWAR-220 / issue #389:
+ * dependencyManagement with overlays should not result in multiple versions
+ * of the same dependency in WEB-INF/lib.
+ *
+ * The overlay-war is built with plexus-utils 3.0.24.
+ * The main-war has dependencyManagement pinning plexus-utils to the managed
+ * version (@plexusUtilVersion@), and uses overlay-war as an overlay.
+ *
+ * If the issue still exists, both versions will appear in main-war's WEB-INF/lib.
+ * If fixed, only the managed version will appear.
+ */
+
+String managedVersion = plexusUtilVersion;
+
+// --- Check overlay WAR content ---
+File overlayTarget = new File( basedir, "overlay-war/target" );
+File overlayWar = new File( overlayTarget, "overlay-war-1.0-SNAPSHOT" );
+File overlayLib = new File( overlayWar, "WEB-INF/lib" );
+
+String[] overlayJars = overlayLib.list();
+boolean overlayHasOld = false;
+boolean overlayHasManaged = false;
+
+for ( int i = 0; i < overlayJars.length; i++ )
+{
+    String jar = overlayJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        overlayHasOld = true;
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        overlayHasManaged = true;
+    }
+}
+
+if ( !overlayHasOld )
+{
+    System.err.println( "Overlay WAR missing plexus-utils-3.0.24.jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( overlayHasManaged )
+{
+    System.err.println( "Overlay WAR unexpectedly contains plexus-utils-" + managedVersion + ".jar. "
+        + "Overlay should only have version 3.0.24." );
+    return false;
+}
+
+System.out.println( "Overlay WAR correctly contains only plexus-utils-3.0.24.jar." );
+
+// --- Check main WAR content ---
+File mainTarget = new File( basedir, "main-war/target" );
+File mainWar = new File( mainTarget, "main-war-1.0-SNAPSHOT" );
+File mainLib = new File( mainWar, "WEB-INF/lib" );
+
+String[] mainJars = mainLib.list();
+boolean mainHasOld = false;
+boolean mainHasManaged = false;
+List duplicateGavs = new ArrayList();
+
+for ( int i = 0; i < mainJars.length; i++ )
+{
+    String jar = mainJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        mainHasOld = true;
+        duplicateGavs.add( "plexus-utils:3.0.24 (" + jar + ")" );
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        mainHasManaged = true;
+        duplicateGavs.add( "plexus-utils:" + managedVersion + " (" + jar + ")" );
+    }
+}
+
+if ( !mainHasManaged )
+{
+    System.err.println( "Main WAR missing plexus-utils-" + managedVersion + ".jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( mainHasOld )
+{
+    // Both versions found -- issue STILL EXISTS
+    System.out.println( "ISSUE #389 (MWAR-220) STILL EXISTS:" );
+    System.out.println( "  Both plexus-utils versions found in main WAR WEB-INF/lib:" );
+    System.out.println( "    - plexus-utils-3.0.24.jar (from overlay unpacking)" );
+    System.out.println( "    - plexus-utils-" + managedVersion + ".jar (from dependencyManagement)" );
+    System.out.println( "  dependencyManagement does not filter overlay-provided jars." );
+    return false;
+}
+else
+{
+    // Only managed version -- issue has been fixed
+    System.out.println( "ISSUE #389 (MWAR-220) APPEARS FIXED:" );

Review Comment:
   remove this; passing tests generate no output



##########
src/it/MWAR-389/verify.bsh:
##########
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.*;
+import java.util.*;
+import org.codehaus.plexus.util.*;
+
+/*
+ * Test for MWAR-220 / issue #389:
+ * dependencyManagement with overlays should not result in multiple versions
+ * of the same dependency in WEB-INF/lib.
+ *
+ * The overlay-war is built with plexus-utils 3.0.24.
+ * The main-war has dependencyManagement pinning plexus-utils to the managed
+ * version (@plexusUtilVersion@), and uses overlay-war as an overlay.
+ *
+ * If the issue still exists, both versions will appear in main-war's WEB-INF/lib.
+ * If fixed, only the managed version will appear.
+ */
+
+String managedVersion = plexusUtilVersion;
+
+// --- Check overlay WAR content ---
+File overlayTarget = new File( basedir, "overlay-war/target" );
+File overlayWar = new File( overlayTarget, "overlay-war-1.0-SNAPSHOT" );
+File overlayLib = new File( overlayWar, "WEB-INF/lib" );
+
+String[] overlayJars = overlayLib.list();
+boolean overlayHasOld = false;
+boolean overlayHasManaged = false;
+
+for ( int i = 0; i < overlayJars.length; i++ )
+{
+    String jar = overlayJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        overlayHasOld = true;
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        overlayHasManaged = true;
+    }
+}
+
+if ( !overlayHasOld )
+{
+    System.err.println( "Overlay WAR missing plexus-utils-3.0.24.jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( overlayHasManaged )
+{
+    System.err.println( "Overlay WAR unexpectedly contains plexus-utils-" + managedVersion + ".jar. "
+        + "Overlay should only have version 3.0.24." );
+    return false;
+}
+
+System.out.println( "Overlay WAR correctly contains only plexus-utils-3.0.24.jar." );
+
+// --- Check main WAR content ---
+File mainTarget = new File( basedir, "main-war/target" );
+File mainWar = new File( mainTarget, "main-war-1.0-SNAPSHOT" );
+File mainLib = new File( mainWar, "WEB-INF/lib" );
+
+String[] mainJars = mainLib.list();
+boolean mainHasOld = false;
+boolean mainHasManaged = false;
+List duplicateGavs = new ArrayList();
+
+for ( int i = 0; i < mainJars.length; i++ )
+{
+    String jar = mainJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        mainHasOld = true;
+        duplicateGavs.add( "plexus-utils:3.0.24 (" + jar + ")" );
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        mainHasManaged = true;
+        duplicateGavs.add( "plexus-utils:" + managedVersion + " (" + jar + ")" );
+    }
+}
+
+if ( !mainHasManaged )
+{
+    System.err.println( "Main WAR missing plexus-utils-" + managedVersion + ".jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( mainHasOld )
+{
+    // Both versions found -- issue STILL EXISTS
+    System.out.println( "ISSUE #389 (MWAR-220) STILL EXISTS:" );
+    System.out.println( "  Both plexus-utils versions found in main WAR WEB-INF/lib:" );
+    System.out.println( "    - plexus-utils-3.0.24.jar (from overlay unpacking)" );
+    System.out.println( "    - plexus-utils-" + managedVersion + ".jar (from dependencyManagement)" );
+    System.out.println( "  dependencyManagement does not filter overlay-provided jars." );
+    return false;
+}
+else
+{
+    // Only managed version -- issue has been fixed
+    System.out.println( "ISSUE #389 (MWAR-220) APPEARS FIXED:" );
+    System.out.println( "  Only plexus-utils-" + managedVersion + ".jar found in WEB-INF/lib." );

Review Comment:
   remove this; passing tests generate no output



##########
src/it/MWAR-389/verify.bsh:
##########
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.*;
+import java.util.*;
+import org.codehaus.plexus.util.*;
+
+/*
+ * Test for MWAR-220 / issue #389:
+ * dependencyManagement with overlays should not result in multiple versions
+ * of the same dependency in WEB-INF/lib.
+ *
+ * The overlay-war is built with plexus-utils 3.0.24.
+ * The main-war has dependencyManagement pinning plexus-utils to the managed
+ * version (@plexusUtilVersion@), and uses overlay-war as an overlay.
+ *
+ * If the issue still exists, both versions will appear in main-war's WEB-INF/lib.
+ * If fixed, only the managed version will appear.
+ */
+
+String managedVersion = plexusUtilVersion;
+
+// --- Check overlay WAR content ---
+File overlayTarget = new File( basedir, "overlay-war/target" );
+File overlayWar = new File( overlayTarget, "overlay-war-1.0-SNAPSHOT" );
+File overlayLib = new File( overlayWar, "WEB-INF/lib" );
+
+String[] overlayJars = overlayLib.list();
+boolean overlayHasOld = false;
+boolean overlayHasManaged = false;
+
+for ( int i = 0; i < overlayJars.length; i++ )
+{
+    String jar = overlayJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        overlayHasOld = true;
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        overlayHasManaged = true;
+    }
+}
+
+if ( !overlayHasOld )
+{
+    System.err.println( "Overlay WAR missing plexus-utils-3.0.24.jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( overlayHasManaged )
+{
+    System.err.println( "Overlay WAR unexpectedly contains plexus-utils-" + managedVersion + ".jar. "
+        + "Overlay should only have version 3.0.24." );
+    return false;
+}
+
+System.out.println( "Overlay WAR correctly contains only plexus-utils-3.0.24.jar." );
+
+// --- Check main WAR content ---
+File mainTarget = new File( basedir, "main-war/target" );
+File mainWar = new File( mainTarget, "main-war-1.0-SNAPSHOT" );
+File mainLib = new File( mainWar, "WEB-INF/lib" );
+
+String[] mainJars = mainLib.list();
+boolean mainHasOld = false;
+boolean mainHasManaged = false;
+List duplicateGavs = new ArrayList();
+
+for ( int i = 0; i < mainJars.length; i++ )
+{
+    String jar = mainJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        mainHasOld = true;
+        duplicateGavs.add( "plexus-utils:3.0.24 (" + jar + ")" );
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        mainHasManaged = true;
+        duplicateGavs.add( "plexus-utils:" + managedVersion + " (" + jar + ")" );
+    }
+}
+
+if ( !mainHasManaged )
+{
+    System.err.println( "Main WAR missing plexus-utils-" + managedVersion + ".jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( mainHasOld )
+{
+    // Both versions found -- issue STILL EXISTS
+    System.out.println( "ISSUE #389 (MWAR-220) STILL EXISTS:" );

Review Comment:
   remove this; passing tests generate no output



##########
src/it/MWAR-389/verify.bsh:
##########
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.*;
+import java.util.*;
+import org.codehaus.plexus.util.*;
+
+/*
+ * Test for MWAR-220 / issue #389:
+ * dependencyManagement with overlays should not result in multiple versions
+ * of the same dependency in WEB-INF/lib.
+ *
+ * The overlay-war is built with plexus-utils 3.0.24.
+ * The main-war has dependencyManagement pinning plexus-utils to the managed
+ * version (@plexusUtilVersion@), and uses overlay-war as an overlay.
+ *
+ * If the issue still exists, both versions will appear in main-war's WEB-INF/lib.
+ * If fixed, only the managed version will appear.
+ */
+
+String managedVersion = plexusUtilVersion;
+
+// --- Check overlay WAR content ---
+File overlayTarget = new File( basedir, "overlay-war/target" );
+File overlayWar = new File( overlayTarget, "overlay-war-1.0-SNAPSHOT" );
+File overlayLib = new File( overlayWar, "WEB-INF/lib" );
+
+String[] overlayJars = overlayLib.list();
+boolean overlayHasOld = false;
+boolean overlayHasManaged = false;
+
+for ( int i = 0; i < overlayJars.length; i++ )
+{
+    String jar = overlayJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        overlayHasOld = true;
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        overlayHasManaged = true;
+    }
+}
+
+if ( !overlayHasOld )
+{
+    System.err.println( "Overlay WAR missing plexus-utils-3.0.24.jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( overlayHasManaged )
+{
+    System.err.println( "Overlay WAR unexpectedly contains plexus-utils-" + managedVersion + ".jar. "
+        + "Overlay should only have version 3.0.24." );
+    return false;
+}
+
+System.out.println( "Overlay WAR correctly contains only plexus-utils-3.0.24.jar." );
+
+// --- Check main WAR content ---
+File mainTarget = new File( basedir, "main-war/target" );
+File mainWar = new File( mainTarget, "main-war-1.0-SNAPSHOT" );
+File mainLib = new File( mainWar, "WEB-INF/lib" );
+
+String[] mainJars = mainLib.list();
+boolean mainHasOld = false;
+boolean mainHasManaged = false;
+List duplicateGavs = new ArrayList();
+
+for ( int i = 0; i < mainJars.length; i++ )
+{
+    String jar = mainJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        mainHasOld = true;
+        duplicateGavs.add( "plexus-utils:3.0.24 (" + jar + ")" );
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        mainHasManaged = true;
+        duplicateGavs.add( "plexus-utils:" + managedVersion + " (" + jar + ")" );
+    }
+}
+
+if ( !mainHasManaged )
+{
+    System.err.println( "Main WAR missing plexus-utils-" + managedVersion + ".jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( mainHasOld )
+{
+    // Both versions found -- issue STILL EXISTS
+    System.out.println( "ISSUE #389 (MWAR-220) STILL EXISTS:" );
+    System.out.println( "  Both plexus-utils versions found in main WAR WEB-INF/lib:" );

Review Comment:
   remove this; passing tests generate no output



##########
src/it/MWAR-389/verify.bsh:
##########
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.*;
+import java.util.*;
+import org.codehaus.plexus.util.*;
+
+/*
+ * Test for MWAR-220 / issue #389:
+ * dependencyManagement with overlays should not result in multiple versions
+ * of the same dependency in WEB-INF/lib.
+ *
+ * The overlay-war is built with plexus-utils 3.0.24.
+ * The main-war has dependencyManagement pinning plexus-utils to the managed
+ * version (@plexusUtilVersion@), and uses overlay-war as an overlay.
+ *
+ * If the issue still exists, both versions will appear in main-war's WEB-INF/lib.
+ * If fixed, only the managed version will appear.
+ */
+
+String managedVersion = plexusUtilVersion;
+
+// --- Check overlay WAR content ---
+File overlayTarget = new File( basedir, "overlay-war/target" );
+File overlayWar = new File( overlayTarget, "overlay-war-1.0-SNAPSHOT" );
+File overlayLib = new File( overlayWar, "WEB-INF/lib" );
+
+String[] overlayJars = overlayLib.list();
+boolean overlayHasOld = false;
+boolean overlayHasManaged = false;
+
+for ( int i = 0; i < overlayJars.length; i++ )
+{
+    String jar = overlayJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        overlayHasOld = true;
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        overlayHasManaged = true;
+    }
+}
+
+if ( !overlayHasOld )
+{
+    System.err.println( "Overlay WAR missing plexus-utils-3.0.24.jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( overlayHasManaged )
+{
+    System.err.println( "Overlay WAR unexpectedly contains plexus-utils-" + managedVersion + ".jar. "
+        + "Overlay should only have version 3.0.24." );
+    return false;
+}
+
+System.out.println( "Overlay WAR correctly contains only plexus-utils-3.0.24.jar." );
+
+// --- Check main WAR content ---
+File mainTarget = new File( basedir, "main-war/target" );
+File mainWar = new File( mainTarget, "main-war-1.0-SNAPSHOT" );
+File mainLib = new File( mainWar, "WEB-INF/lib" );
+
+String[] mainJars = mainLib.list();
+boolean mainHasOld = false;
+boolean mainHasManaged = false;
+List duplicateGavs = new ArrayList();
+
+for ( int i = 0; i < mainJars.length; i++ )
+{
+    String jar = mainJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        mainHasOld = true;
+        duplicateGavs.add( "plexus-utils:3.0.24 (" + jar + ")" );
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        mainHasManaged = true;
+        duplicateGavs.add( "plexus-utils:" + managedVersion + " (" + jar + ")" );
+    }
+}
+
+if ( !mainHasManaged )
+{
+    System.err.println( "Main WAR missing plexus-utils-" + managedVersion + ".jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( mainHasOld )
+{
+    // Both versions found -- issue STILL EXISTS
+    System.out.println( "ISSUE #389 (MWAR-220) STILL EXISTS:" );
+    System.out.println( "  Both plexus-utils versions found in main WAR WEB-INF/lib:" );
+    System.out.println( "    - plexus-utils-3.0.24.jar (from overlay unpacking)" );
+    System.out.println( "    - plexus-utils-" + managedVersion + ".jar (from dependencyManagement)" );

Review Comment:
   remove this; passing tests generate no output



##########
src/it/MWAR-389/verify.bsh:
##########
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.*;
+import java.util.*;
+import org.codehaus.plexus.util.*;
+
+/*
+ * Test for MWAR-220 / issue #389:
+ * dependencyManagement with overlays should not result in multiple versions
+ * of the same dependency in WEB-INF/lib.
+ *
+ * The overlay-war is built with plexus-utils 3.0.24.
+ * The main-war has dependencyManagement pinning plexus-utils to the managed
+ * version (@plexusUtilVersion@), and uses overlay-war as an overlay.
+ *
+ * If the issue still exists, both versions will appear in main-war's WEB-INF/lib.
+ * If fixed, only the managed version will appear.
+ */
+
+String managedVersion = plexusUtilVersion;
+
+// --- Check overlay WAR content ---
+File overlayTarget = new File( basedir, "overlay-war/target" );
+File overlayWar = new File( overlayTarget, "overlay-war-1.0-SNAPSHOT" );
+File overlayLib = new File( overlayWar, "WEB-INF/lib" );
+
+String[] overlayJars = overlayLib.list();
+boolean overlayHasOld = false;
+boolean overlayHasManaged = false;
+
+for ( int i = 0; i < overlayJars.length; i++ )
+{
+    String jar = overlayJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        overlayHasOld = true;
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        overlayHasManaged = true;
+    }
+}
+
+if ( !overlayHasOld )
+{
+    System.err.println( "Overlay WAR missing plexus-utils-3.0.24.jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( overlayHasManaged )
+{
+    System.err.println( "Overlay WAR unexpectedly contains plexus-utils-" + managedVersion + ".jar. "
+        + "Overlay should only have version 3.0.24." );
+    return false;
+}
+
+System.out.println( "Overlay WAR correctly contains only plexus-utils-3.0.24.jar." );
+
+// --- Check main WAR content ---
+File mainTarget = new File( basedir, "main-war/target" );
+File mainWar = new File( mainTarget, "main-war-1.0-SNAPSHOT" );
+File mainLib = new File( mainWar, "WEB-INF/lib" );
+
+String[] mainJars = mainLib.list();
+boolean mainHasOld = false;
+boolean mainHasManaged = false;
+List duplicateGavs = new ArrayList();
+
+for ( int i = 0; i < mainJars.length; i++ )
+{
+    String jar = mainJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        mainHasOld = true;
+        duplicateGavs.add( "plexus-utils:3.0.24 (" + jar + ")" );
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        mainHasManaged = true;
+        duplicateGavs.add( "plexus-utils:" + managedVersion + " (" + jar + ")" );
+    }
+}
+
+if ( !mainHasManaged )
+{
+    System.err.println( "Main WAR missing plexus-utils-" + managedVersion + ".jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( mainHasOld )
+{
+    // Both versions found -- issue STILL EXISTS
+    System.out.println( "ISSUE #389 (MWAR-220) STILL EXISTS:" );
+    System.out.println( "  Both plexus-utils versions found in main WAR WEB-INF/lib:" );
+    System.out.println( "    - plexus-utils-3.0.24.jar (from overlay unpacking)" );
+    System.out.println( "    - plexus-utils-" + managedVersion + ".jar (from dependencyManagement)" );
+    System.out.println( "  dependencyManagement does not filter overlay-provided jars." );

Review Comment:
   remove this; passing tests generate no output



##########
src/it/MWAR-389/verify.bsh:
##########
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.*;
+import java.util.*;
+import org.codehaus.plexus.util.*;
+
+/*
+ * Test for MWAR-220 / issue #389:
+ * dependencyManagement with overlays should not result in multiple versions
+ * of the same dependency in WEB-INF/lib.
+ *
+ * The overlay-war is built with plexus-utils 3.0.24.
+ * The main-war has dependencyManagement pinning plexus-utils to the managed
+ * version (@plexusUtilVersion@), and uses overlay-war as an overlay.
+ *
+ * If the issue still exists, both versions will appear in main-war's WEB-INF/lib.
+ * If fixed, only the managed version will appear.
+ */
+
+String managedVersion = plexusUtilVersion;
+
+// --- Check overlay WAR content ---
+File overlayTarget = new File( basedir, "overlay-war/target" );
+File overlayWar = new File( overlayTarget, "overlay-war-1.0-SNAPSHOT" );
+File overlayLib = new File( overlayWar, "WEB-INF/lib" );
+
+String[] overlayJars = overlayLib.list();
+boolean overlayHasOld = false;
+boolean overlayHasManaged = false;
+
+for ( int i = 0; i < overlayJars.length; i++ )
+{
+    String jar = overlayJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        overlayHasOld = true;
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        overlayHasManaged = true;
+    }
+}
+
+if ( !overlayHasOld )
+{
+    System.err.println( "Overlay WAR missing plexus-utils-3.0.24.jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( overlayHasManaged )
+{
+    System.err.println( "Overlay WAR unexpectedly contains plexus-utils-" + managedVersion + ".jar. "
+        + "Overlay should only have version 3.0.24." );
+    return false;
+}
+
+System.out.println( "Overlay WAR correctly contains only plexus-utils-3.0.24.jar." );
+
+// --- Check main WAR content ---
+File mainTarget = new File( basedir, "main-war/target" );
+File mainWar = new File( mainTarget, "main-war-1.0-SNAPSHOT" );
+File mainLib = new File( mainWar, "WEB-INF/lib" );
+
+String[] mainJars = mainLib.list();
+boolean mainHasOld = false;
+boolean mainHasManaged = false;
+List duplicateGavs = new ArrayList();
+
+for ( int i = 0; i < mainJars.length; i++ )
+{
+    String jar = mainJars[i];
+    if ( jar.startsWith( "plexus-utils-3.0.24" ) )
+    {
+        mainHasOld = true;
+        duplicateGavs.add( "plexus-utils:3.0.24 (" + jar + ")" );
+    }
+    if ( jar.startsWith( "plexus-utils-" + managedVersion ) )
+    {
+        mainHasManaged = true;
+        duplicateGavs.add( "plexus-utils:" + managedVersion + " (" + jar + ")" );
+    }
+}
+
+if ( !mainHasManaged )
+{
+    System.err.println( "Main WAR missing plexus-utils-" + managedVersion + ".jar in WEB-INF/lib." );
+    return false;
+}
+
+if ( mainHasOld )
+{
+    // Both versions found -- issue STILL EXISTS
+    System.out.println( "ISSUE #389 (MWAR-220) STILL EXISTS:" );
+    System.out.println( "  Both plexus-utils versions found in main WAR WEB-INF/lib:" );
+    System.out.println( "    - plexus-utils-3.0.24.jar (from overlay unpacking)" );
+    System.out.println( "    - plexus-utils-" + managedVersion + ".jar (from dependencyManagement)" );
+    System.out.println( "  dependencyManagement does not filter overlay-provided jars." );
+    return false;
+}
+else
+{
+    // Only managed version -- issue has been fixed
+    System.out.println( "ISSUE #389 (MWAR-220) APPEARS FIXED:" );
+    System.out.println( "  Only plexus-utils-" + managedVersion + ".jar found in WEB-INF/lib." );
+    System.out.println( "  The overlay's plexus-utils-3.0.24.jar was correctly filtered out." );

Review Comment:
   remove this; passing tests generate no output



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [MWAR-220] filter overlay jars conflicting with managed dependencies [maven-war-plugin]

Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #639:
URL: https://github.com/apache/maven-war-plugin/pull/639#discussion_r3665270403


##########
src/main/java/org/apache/maven/plugins/war/packaging/OverlayPackagingTask.java:
##########
@@ -127,4 +137,96 @@ protected File getOverlayTempDirectory(WarPackagingContext context, Overlay over
         }
         return result;
     }
+
+    /**
+     * Identifies jars from the overlay's {@code WEB-INF/lib} whose artifactId matches a non-optional
+     * runtime-scope dependency resolved by the project. These jars are candidates for exclusion
+     * from the overlay copy so that only the project-resolved version ends up in {@code WEB-INF/lib}.
+     *
+     * <p>The overlay's cached unpack directory is <em>not</em> mutated; the returned set is used
+     * as additional excludes during the copy step.
+     *
+     * @param context the packaging context
+     * @param overlayDir the unpacked overlay directory
+     * @return set of paths (relative to the overlay dir) to exclude from the overlay copy
+     */
+    private Set<String> computeConflictingJars(WarPackagingContext context, File overlayDir) {
+        File libDir = new File(overlayDir, "WEB-INF/lib");
+        if (!libDir.isDirectory()) {
+            return Collections.emptySet();
+        }
+
+        ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME);
+        Set<String> projectArtifactIds = new HashSet<>();
+        for (Artifact artifact : context.getProject().getArtifacts()) {
+            if (!artifact.isOptional() && filter.include(artifact) && "jar".equals(artifact.getType())) {
+                projectArtifactIds.add(artifact.getArtifactId());
+            }
+        }

Review Comment:
   Conflict matching is done on `artifactId` only, which can incorrectly exclude an overlay jar when two different dependencies share the same artifactId across different groupIds (leading to missing/incorrect jars in the final WAR). A more reliable approach is to read `META-INF/maven/**/pom.properties` from the overlay jar to obtain groupId/artifactId (and optionally version), then compare against the project’s resolved artifacts by groupId+artifactId.



##########
src/main/java/org/apache/maven/plugins/war/packaging/OverlayPackagingTask.java:
##########
@@ -127,4 +137,96 @@ protected File getOverlayTempDirectory(WarPackagingContext context, Overlay over
         }
         return result;
     }
+
+    /**
+     * Identifies jars from the overlay's {@code WEB-INF/lib} whose artifactId matches a non-optional
+     * runtime-scope dependency resolved by the project. These jars are candidates for exclusion
+     * from the overlay copy so that only the project-resolved version ends up in {@code WEB-INF/lib}.
+     *
+     * <p>The overlay's cached unpack directory is <em>not</em> mutated; the returned set is used
+     * as additional excludes during the copy step.
+     *
+     * @param context the packaging context
+     * @param overlayDir the unpacked overlay directory
+     * @return set of paths (relative to the overlay dir) to exclude from the overlay copy
+     */
+    private Set<String> computeConflictingJars(WarPackagingContext context, File overlayDir) {
+        File libDir = new File(overlayDir, "WEB-INF/lib");
+        if (!libDir.isDirectory()) {
+            return Collections.emptySet();
+        }
+
+        ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME);
+        Set<String> projectArtifactIds = new HashSet<>();
+        for (Artifact artifact : context.getProject().getArtifacts()) {
+            if (!artifact.isOptional() && filter.include(artifact) && "jar".equals(artifact.getType())) {
+                projectArtifactIds.add(artifact.getArtifactId());
+            }
+        }
+
+        if (projectArtifactIds.isEmpty()) {
+            return Collections.emptySet();
+        }
+
+        File[] overlayJars = libDir.listFiles((dir, name) -> name.endsWith(".jar"));
+        if (overlayJars == null) {
+            return Collections.emptySet();
+        }
+
+        Set<String> conflicting = new HashSet<>();
+        for (File overlayJar : overlayJars) {
+            String jarName = overlayJar.getName();
+            String artifactId = extractArtifactId(jarName);
+            if (artifactId != null && projectArtifactIds.contains(artifactId)) {
+                context.getLog()
+                        .debug("Excluding dependency [" + jarName + "] from overlay [" + overlay.getId()
+                                + "]; project runtime dependencies already include a version");
+                conflicting.add("WEB-INF/lib/" + jarName);
+            }
+        }

Review Comment:
   `overlay` is referenced in the log message but is not in scope in `computeConflictingJars(...)`, which will not compile. Pass the `Overlay` (or overlay id) into `computeConflictingJars(...)` and use that parameter in the log message, or remove the overlay id from the message.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [MWAR-220] filter overlay jars conflicting with managed dependencies [maven-war-plugin]

Posted by "Copilot (via GitHub)" <gi...@apache.org>.
Copilot commented on code in PR #639:
URL: https://github.com/apache/maven-war-plugin/pull/639#discussion_r3652633508


##########
src/main/java/org/apache/maven/plugins/war/packaging/OverlayPackagingTask.java:
##########
@@ -61,6 +64,9 @@ public void performPackaging(WarPackagingContext context) throws MojoExecutionEx
                 // Step1: Extract if necessary
                 final File tmpDir = unpackOverlay(context, overlay);
 
+                // Step1b: Remove jars from overlay that conflict with managed dependencies
+                filterConflictingDependencyJars(context, tmpDir);
+

Review Comment:
   filterConflictingDependencyJars() deletes jars from the overlay unpack directory (tmpDir). Because unpackOverlay() reuses that directory when it’s non-empty and newer than the overlay artifact, this permanently mutates the cached unpacked overlay and can affect subsequent builds (e.g., if dependencyManagement changes, or if another execution expects the original overlay contents). Consider avoiding in-place mutation (e.g., exclude during copy, unpack into a per-execution directory, or restore/re-unpack after copying when deletions occurred).



##########
src/main/java/org/apache/maven/plugins/war/packaging/OverlayPackagingTask.java:
##########
@@ -127,4 +133,72 @@ protected File getOverlayTempDirectory(WarPackagingContext context, Overlay over
         }
         return result;
     }
+
+    /**
+     * Removes jars from the overlay's {@code WEB-INF/lib} that conflict with the project's managed
+     * dependencies. When a project uses dependencyManagement to pin a version, any jar from the
+     * overlay with the same artifactId but a different version is removed, ensuring only the
+     * dependency-managed version ends up in {@code WEB-INF/lib}.
+     *
+     * @param context the packaging context
+     * @param overlayDir the unpacked overlay directory
+     */
+    private void filterConflictingDependencyJars(WarPackagingContext context, File overlayDir) {
+        File libDir = new File(overlayDir, "WEB-INF/lib");
+        if (!libDir.isDirectory()) {
+            return;
+        }
+
+        Set<String> projectArtifactIds = new HashSet<>();
+        for (Artifact artifact : context.getProject().getArtifacts()) {
+            if (!artifact.isOptional() && "jar".equals(artifact.getType())) {
+                projectArtifactIds.add(artifact.getArtifactId());
+            }
+        }

Review Comment:
   filterConflictingDependencyJars() builds the projectArtifactIds set from all project artifacts, but ArtifactsPackagingTask only packages runtime-scope artifacts (ScopeArtifactFilter(Artifact.SCOPE_RUNTIME)). This can cause overlay jars to be deleted even when the corresponding project artifact won’t be packaged into WEB-INF/lib (e.g., provided scope), resulting in a missing dependency at runtime.



##########
src/main/java/org/apache/maven/plugins/war/packaging/OverlayPackagingTask.java:
##########
@@ -127,4 +133,72 @@ protected File getOverlayTempDirectory(WarPackagingContext context, Overlay over
         }
         return result;
     }
+
+    /**
+     * Removes jars from the overlay's {@code WEB-INF/lib} that conflict with the project's managed
+     * dependencies. When a project uses dependencyManagement to pin a version, any jar from the
+     * overlay with the same artifactId but a different version is removed, ensuring only the
+     * dependency-managed version ends up in {@code WEB-INF/lib}.
+     *
+     * @param context the packaging context
+     * @param overlayDir the unpacked overlay directory
+     */
+    private void filterConflictingDependencyJars(WarPackagingContext context, File overlayDir) {
+        File libDir = new File(overlayDir, "WEB-INF/lib");
+        if (!libDir.isDirectory()) {
+            return;
+        }
+
+        Set<String> projectArtifactIds = new HashSet<>();
+        for (Artifact artifact : context.getProject().getArtifacts()) {
+            if (!artifact.isOptional() && "jar".equals(artifact.getType())) {
+                projectArtifactIds.add(artifact.getArtifactId());
+            }
+        }
+
+        if (projectArtifactIds.isEmpty()) {
+            return;
+        }
+
+        File[] overlayJars = libDir.listFiles((dir, name) -> name.endsWith(".jar"));
+        if (overlayJars == null) {
+            return;
+        }
+
+        for (File overlayJar : overlayJars) {
+            String jarName = overlayJar.getName();
+            String artifactId = extractArtifactId(jarName);
+            if (artifactId != null && projectArtifactIds.contains(artifactId)) {
+                context.getLog()
+                        .debug("Removing dependency [" + jarName + "] from overlay [" + overlay.getId()
+                                + "]; managed version in project already provides it");
+                overlayJar.delete();
+            }

Review Comment:
   overlayJar.delete() return value is ignored. If the delete fails, the log still claims the jar was removed, and duplicate versions may remain in the final WAR without any signal.



##########
src/it/MWAR-389/verify.bsh:
##########
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.io.*;
+import org.codehaus.plexus.util.*;
+
+/*
+ * Test for MWAR-220 / issue #389:
+ * dependencyManagement with overlays should not result in multiple versions
+ * of the same dependency in WEB-INF/lib.
+ *
+ * The overlay-war is built with plexus-utils 3.0.24.
+ * The main-war has dependencyManagement pinning plexus-utils to the managed
+ * version (@plexusUtilVersion@), and uses overlay-war as an overlay.
+ *
+ * If the issue still exists, both versions will appear in main-war's WEB-INF/lib.
+ * If fixed, only the managed version will appear.
+ */
+
+String managedVersion = plexusUtilVersion;
+
+// --- Check overlay WAR content ---
+File overlayTarget = new File( basedir, "overlay-war/target" );
+File overlayWar = new File( overlayTarget, "overlay-war-1.0-SNAPSHOT" );
+File overlayLib = new File( overlayWar, "WEB-INF/lib" );
+
+String[] overlayJars = overlayLib.list();
+boolean overlayHasOld = false;
+boolean overlayHasManaged = false;
+
+for ( int i = 0; i < overlayJars.length; i++ )

Review Comment:
   overlayLib.list() can return null (missing directory / IO error), which will cause a NullPointerException when accessing overlayJars.length. Other IT verify scripts check directory existence before listing.
   
   This issue also appears on line 80 of the same file.



##########
src/main/java/org/apache/maven/plugins/war/packaging/OverlayPackagingTask.java:
##########
@@ -127,4 +133,72 @@ protected File getOverlayTempDirectory(WarPackagingContext context, Overlay over
         }
         return result;
     }
+
+    /**
+     * Removes jars from the overlay's {@code WEB-INF/lib} that conflict with the project's managed
+     * dependencies. When a project uses dependencyManagement to pin a version, any jar from the
+     * overlay with the same artifactId but a different version is removed, ensuring only the
+     * dependency-managed version ends up in {@code WEB-INF/lib}.
+     *
+     * @param context the packaging context
+     * @param overlayDir the unpacked overlay directory
+     */
+    private void filterConflictingDependencyJars(WarPackagingContext context, File overlayDir) {
+        File libDir = new File(overlayDir, "WEB-INF/lib");
+        if (!libDir.isDirectory()) {
+            return;
+        }
+
+        Set<String> projectArtifactIds = new HashSet<>();
+        for (Artifact artifact : context.getProject().getArtifacts()) {
+            if (!artifact.isOptional() && "jar".equals(artifact.getType())) {
+                projectArtifactIds.add(artifact.getArtifactId());
+            }
+        }
+
+        if (projectArtifactIds.isEmpty()) {
+            return;
+        }
+
+        File[] overlayJars = libDir.listFiles((dir, name) -> name.endsWith(".jar"));
+        if (overlayJars == null) {
+            return;
+        }
+
+        for (File overlayJar : overlayJars) {
+            String jarName = overlayJar.getName();
+            String artifactId = extractArtifactId(jarName);
+            if (artifactId != null && projectArtifactIds.contains(artifactId)) {
+                context.getLog()
+                        .debug("Removing dependency [" + jarName + "] from overlay [" + overlay.getId()
+                                + "]; managed version in project already provides it");
+                overlayJar.delete();
+            }
+        }
+    }
+
+    /**
+     * Extracts the Maven artifactId from a jar filename following the
+     * {@code artifactId-version(-classifier)?.jar} convention.
+     *
+     * @param jarName the jar filename
+     * @return the artifactId, or null if it cannot be determined
+     */
+    private static String extractArtifactId(String jarName) {
+        if (jarName == null || !jarName.endsWith(".jar")) {
+            return null;
+        }
+        String baseName = jarName.substring(0, jarName.length() - 4);
+        int versionStart = -1;
+        for (int i = 0; i < baseName.length(); i++) {
+            if (Character.isDigit(baseName.charAt(i))) {
+                versionStart = i;
+                break;
+            }
+        }
+        if (versionStart > 0 && baseName.charAt(versionStart - 1) == '-') {
+            return baseName.substring(0, versionStart - 1);
+        }
+        return null;
+    }

Review Comment:
   extractArtifactId() assumes the first digit in the filename starts the version. This fails for common artifactIds containing digits (e.g., log4j-api-2.24.0.jar) and will silently skip filtering those conflicts.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Re: [PR] [MWAR-220] filter overlay jars conflicting with managed dependencies [maven-war-plugin]

Posted by "elharo (via GitHub)" <gi...@apache.org>.
elharo commented on code in PR #639:
URL: https://github.com/apache/maven-war-plugin/pull/639#discussion_r3665548504


##########
src/main/java/org/apache/maven/plugins/war/packaging/OverlayPackagingTask.java:
##########
@@ -127,4 +137,96 @@ protected File getOverlayTempDirectory(WarPackagingContext context, Overlay over
         }
         return result;
     }
+
+    /**
+     * Identifies jars from the overlay's {@code WEB-INF/lib} whose artifactId matches a non-optional
+     * runtime-scope dependency resolved by the project. These jars are candidates for exclusion
+     * from the overlay copy so that only the project-resolved version ends up in {@code WEB-INF/lib}.
+     *
+     * <p>The overlay's cached unpack directory is <em>not</em> mutated; the returned set is used
+     * as additional excludes during the copy step.
+     *
+     * @param context the packaging context
+     * @param overlayDir the unpacked overlay directory
+     * @return set of paths (relative to the overlay dir) to exclude from the overlay copy
+     */
+    private Set<String> computeConflictingJars(WarPackagingContext context, File overlayDir) {
+        File libDir = new File(overlayDir, "WEB-INF/lib");
+        if (!libDir.isDirectory()) {
+            return Collections.emptySet();
+        }
+
+        ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME);
+        Set<String> projectArtifactIds = new HashSet<>();
+        for (Artifact artifact : context.getProject().getArtifacts()) {
+            if (!artifact.isOptional() && filter.include(artifact) && "jar".equals(artifact.getType())) {
+                projectArtifactIds.add(artifact.getArtifactId());
+            }
+        }
+
+        if (projectArtifactIds.isEmpty()) {
+            return Collections.emptySet();
+        }
+
+        File[] overlayJars = libDir.listFiles((dir, name) -> name.endsWith(".jar"));
+        if (overlayJars == null) {
+            return Collections.emptySet();
+        }
+
+        Set<String> conflicting = new HashSet<>();
+        for (File overlayJar : overlayJars) {
+            String jarName = overlayJar.getName();
+            String artifactId = extractArtifactId(jarName);
+            if (artifactId != null && projectArtifactIds.contains(artifactId)) {
+                context.getLog()
+                        .debug("Excluding dependency [" + jarName + "] from overlay [" + overlay.getId()
+                                + "]; project runtime dependencies already include a version");
+                conflicting.add("WEB-INF/lib/" + jarName);
+            }
+        }

Review Comment:
   `overlay` is a field of `OverlayPackagingTask` (line 46: `private final Overlay overlay;`). Since `computeConflictingJars` is an instance method, `this.overlay` is accessible in scope. The code compiles and runs correctly.



##########
src/main/java/org/apache/maven/plugins/war/packaging/OverlayPackagingTask.java:
##########
@@ -127,4 +137,96 @@ protected File getOverlayTempDirectory(WarPackagingContext context, Overlay over
         }
         return result;
     }
+
+    /**
+     * Identifies jars from the overlay's {@code WEB-INF/lib} whose artifactId matches a non-optional
+     * runtime-scope dependency resolved by the project. These jars are candidates for exclusion
+     * from the overlay copy so that only the project-resolved version ends up in {@code WEB-INF/lib}.
+     *
+     * <p>The overlay's cached unpack directory is <em>not</em> mutated; the returned set is used
+     * as additional excludes during the copy step.
+     *
+     * @param context the packaging context
+     * @param overlayDir the unpacked overlay directory
+     * @return set of paths (relative to the overlay dir) to exclude from the overlay copy
+     */
+    private Set<String> computeConflictingJars(WarPackagingContext context, File overlayDir) {
+        File libDir = new File(overlayDir, "WEB-INF/lib");
+        if (!libDir.isDirectory()) {
+            return Collections.emptySet();
+        }
+
+        ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME);
+        Set<String> projectArtifactIds = new HashSet<>();
+        for (Artifact artifact : context.getProject().getArtifacts()) {
+            if (!artifact.isOptional() && filter.include(artifact) && "jar".equals(artifact.getType())) {
+                projectArtifactIds.add(artifact.getArtifactId());
+            }
+        }

Review Comment:
   Addressed in commit fc54f70. Added `getJarGroupId()` which reads `META-INF/maven/**/pom.properties` from each overlay jar to obtain the groupId for precise `groupId:artifactId` matching. Falls back to artifactId-only matching when the metadata is absent.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: issues-unsubscribe@maven.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org