[MSHADE-364] drop duplicate resource warning when the resource is handled by a transformer
diff --git a/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java b/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java
index f5897c3..15712ad 100644
--- a/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java
+++ b/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java
@@ -256,6 +256,10 @@
 
                     addResource( resources, jos, mappedName, entry.getTime(), in );
                 }
+                else
+                {
+                    duplicates.remove( name, jar );
+                }
             }
         }
     }
@@ -338,11 +342,25 @@
             final Collection<String> overlaps = new ArrayList<>();
             if ( !classes.isEmpty() )
             {
-                overlaps.add( "classes" );
+                if ( resources.size() == 1 )
+                {
+                    overlaps.add( "class" );
+                }
+                else
+                {
+                    overlaps.add( "classes" );
+                }
             }
             if ( !resources.isEmpty() )
             {
-                overlaps.add( "resources" );
+                if ( resources.size() == 1 )
+                {
+                    overlaps.add( "resource" );
+                }
+                else
+                {
+                    overlaps.add( "resources" );
+                }
             }
 
             final List<String> all = new ArrayList<>( classes.size() + resources.size() );
diff --git a/src/test/java/org/apache/maven/plugins/shade/DefaultShaderTest.java b/src/test/java/org/apache/maven/plugins/shade/DefaultShaderTest.java
index efeffe5..012a366 100644
--- a/src/test/java/org/apache/maven/plugins/shade/DefaultShaderTest.java
+++ b/src/test/java/org/apache/maven/plugins/shade/DefaultShaderTest.java
@@ -20,15 +20,20 @@
  */
 
 import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.lang.reflect.Field;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
 
 import junit.framework.TestCase;
 
@@ -36,11 +41,15 @@
 import org.apache.maven.plugins.shade.filter.Filter;
 import org.apache.maven.plugins.shade.relocation.Relocator;
 import org.apache.maven.plugins.shade.relocation.SimpleRelocator;
+import org.apache.maven.plugins.shade.resource.AppendingTransformer;
 import org.apache.maven.plugins.shade.resource.ComponentsXmlResourceTransformer;
+import org.apache.maven.plugins.shade.resource.ManifestResourceTransformer;
 import org.apache.maven.plugins.shade.resource.ResourceTransformer;
 import org.codehaus.plexus.logging.AbstractLogger;
 import org.codehaus.plexus.logging.Logger;
 import org.codehaus.plexus.logging.console.ConsoleLogger;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.Opcodes;
@@ -57,47 +66,8 @@
 
     public void testOverlappingResourcesAreLogged() throws IOException, MojoExecutionException {
         final DefaultShader shader = new DefaultShader();
-        final List<String> debugMessages = new ArrayList<>();
-        final List<String> warnMessages = new ArrayList<>();
-        shader.enableLogging( new AbstractLogger(
-                Logger.LEVEL_INFO, "TEST_DefaultShaderTest_testOverlappingResourcesAreLogged" )
-        {
-            @Override
-            public void debug( final String s, final Throwable throwable )
-            {
-                debugMessages.add( s.replace( '\\', '/' ).trim() );
-            }
-
-            @Override
-            public void info( final String s, final Throwable throwable )
-            {
-                // no-op
-            }
-
-            @Override
-            public void warn( final String s, final Throwable throwable )
-            {
-                warnMessages.add( s.replace( '\\', '/' ).trim() );
-            }
-
-            @Override
-            public void error( final String s, final Throwable throwable )
-            {
-                // no-op
-            }
-
-            @Override
-            public void fatalError( final String s, final Throwable throwable )
-            {
-                // no-op
-            }
-
-            @Override
-            public Logger getChildLogger( final String s )
-            {
-                return this;
-            }
-        });
+        final MockLogger logs = new MockLogger();
+        shader.enableLogging(logs);
 
         // we will shade two jars and expect to see META-INF/MANIFEST.MF overlaps, this will always be true
         // but this can lead to a broken deployment if intended for OSGi or so, so even this should be logged
@@ -113,16 +83,67 @@
         shadeRequest.setUberJar( new File( "target/foo-custom_testOverlappingResourcesAreLogged.jar" ) );
         shader.shade( shadeRequest );
 
-        final String failureWarnMessage = warnMessages.toString();
-        assertTrue(failureWarnMessage, warnMessages.contains(
-                "plexus-utils-1.4.1.jar, test-project-1.0-SNAPSHOT.jar define 1 overlapping resources:"));
-        assertTrue(failureWarnMessage, warnMessages.contains("- META-INF/MANIFEST.MF"));
+        final String failureWarnMessage = logs.warnMessages.toString();
+        assertTrue(failureWarnMessage, logs.warnMessages.contains(
+                "plexus-utils-1.4.1.jar, test-project-1.0-SNAPSHOT.jar define 1 overlapping resource:"));
+        assertTrue(failureWarnMessage, logs.warnMessages.contains("- META-INF/MANIFEST.MF"));
 
-        final String failureDebugMessage = debugMessages.toString();
-        assertTrue(failureDebugMessage, debugMessages.contains(
+        final String failureDebugMessage = logs.debugMessages.toString();
+        assertTrue(failureDebugMessage, logs.debugMessages.contains(
                 "We have a duplicate META-INF/MANIFEST.MF in src/test/jars/plexus-utils-1.4.1.jar" ));
     }
 
+    public void testOverlappingResourcesAreLoggedExceptATransformerHandlesIt() throws Exception {
+        TemporaryFolder temporaryFolder = new TemporaryFolder();
+        Set<File> set = new LinkedHashSet<>();
+        temporaryFolder.create();
+        File j1 = temporaryFolder.newFile("j1.jar");
+        try ( JarOutputStream jos = new JarOutputStream(new FileOutputStream( j1 ) ) )
+        {
+            jos.putNextEntry(new JarEntry( "foo.txt" ));
+            jos.write("c1".getBytes(StandardCharsets.UTF_8));
+            jos.closeEntry();
+        }
+        File j2 = temporaryFolder.newFile("j2.jar");
+        try ( JarOutputStream jos = new JarOutputStream(new FileOutputStream( j2 ) ) )
+        {
+            jos.putNextEntry(new JarEntry( "foo.txt" ));
+            jos.write("c2".getBytes(StandardCharsets.UTF_8));
+            jos.closeEntry();
+        }
+        set.add( j1 );
+        set.add( j2 );
+
+        AppendingTransformer transformer = new AppendingTransformer();
+        Field resource = AppendingTransformer.class.getDeclaredField( "resource" );
+        resource.setAccessible( true );
+        resource.set( transformer, "foo.txt" );
+
+        ShadeRequest shadeRequest = new ShadeRequest();
+        shadeRequest.setJars( set );
+        shadeRequest.setRelocators( Collections.<Relocator>emptyList() );
+        shadeRequest.setResourceTransformers( Collections.<ResourceTransformer>singletonList( transformer) );
+        shadeRequest.setFilters( Collections.<Filter>emptyList() );
+        shadeRequest.setUberJar( new File( "target/foo-custom_testOverlappingResourcesAreLogged.jar" ) );
+
+        DefaultShader shaderWithTransformer = new DefaultShader();
+        final MockLogger logWithTransformer = new MockLogger();
+        shaderWithTransformer.enableLogging( logWithTransformer );
+        shaderWithTransformer.shade( shadeRequest );
+
+        DefaultShader shaderWithoutTransformer = new DefaultShader();
+        MockLogger logWithoutTransformer = new MockLogger();
+        shaderWithoutTransformer.enableLogging( logWithoutTransformer );
+        shadeRequest.setResourceTransformers( Collections.<ResourceTransformer>emptyList() );
+        shaderWithoutTransformer.shade( shadeRequest );
+
+        temporaryFolder.delete();
+
+        assertTrue(logWithTransformer.warnMessages.toString(), logWithTransformer.warnMessages.isEmpty());
+        assertTrue(logWithoutTransformer.warnMessages.toString(), logWithoutTransformer.warnMessages.containsAll(
+               Arrays.<String>asList( "j1.jar, j2.jar define 1 overlapping resource:", "- foo.txt" ) ) );
+    }
+
     public void testShaderWithDefaultShadedPattern()
         throws Exception
     {
@@ -274,4 +295,50 @@
         return s;
     }
 
+    private static class MockLogger extends AbstractLogger
+    {
+        private final List<String> debugMessages = new ArrayList<>();
+        private final List<String> warnMessages = new ArrayList<>();
+
+        private MockLogger()
+        {
+            super( Logger.LEVEL_INFO, "test" );
+        }
+
+        @Override
+        public void debug( String s, Throwable throwable )
+        {
+            debugMessages.add( s.replace( '\\', '/' ).trim() );
+        }
+
+        @Override
+        public void info( String s, Throwable throwable )
+        {
+            // no-op
+        }
+
+        @Override
+        public void warn( String s, Throwable throwable )
+        {
+            warnMessages.add( s.replace( '\\', '/' ).trim() );
+        }
+
+        @Override
+        public void error( String s, Throwable throwable )
+        {
+            // no-op
+        }
+
+        @Override
+        public void fatalError( String s, Throwable throwable )
+        {
+            // no-op
+        }
+
+        @Override
+        public Logger getChildLogger( String s )
+        {
+            return this;
+        }
+    }
 }