You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by hb...@apache.org on 2020/04/08 22:39:45 UTC

[maven-shade-plugin] branch master updated: [MSHADE-352] make timestamp of transformed resources reproducible

This is an automated email from the ASF dual-hosted git repository.

hboutemy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-shade-plugin.git


The following commit(s) were added to refs/heads/master by this push:
     new 0d7bfb5  [MSHADE-352] make timestamp of transformed resources reproducible
0d7bfb5 is described below

commit 0d7bfb53a5fd83eede7edfd5552db5fa561d6286
Author: Hervé Boutemy <hb...@apache.org>
AuthorDate: Thu Apr 9 00:39:20 2020 +0200

    [MSHADE-352] make timestamp of transformed resources reproducible
---
 .../apache/maven/plugins/shade/DefaultShader.java   | 21 +++++++++++----------
 .../resource/ApacheLicenseResourceTransformer.java  |  3 +--
 .../resource/ApacheNoticeResourceTransformer.java   | 12 ++++++++++--
 .../shade/resource/AppendingTransformer.java        | 12 ++++++++++--
 .../resource/ComponentsXmlResourceTransformer.java  | 14 ++++++++++++--
 .../resource/DontIncludeResourceTransformer.java    |  2 +-
 .../shade/resource/GroovyResourceTransformer.java   | 13 +++++++++++--
 .../shade/resource/IncludeResourceTransformer.java  | 14 +++++++++++---
 .../shade/resource/ManifestResourceTransformer.java | 15 ++++++++++++---
 .../resource/PluginXmlResourceTransformer.java      | 13 +++++++++++--
 .../ResourceBundleAppendingTransformer.java         | 18 ++++++++++++++----
 .../plugins/shade/resource/ResourceTransformer.java |  3 ++-
 .../shade/resource/ServicesResourceTransformer.java | 21 +++++++++++++--------
 .../shade/resource/XmlAppendingTransformer.java     | 13 +++++++++++--
 .../resource/properties/PropertiesTransformer.java  | 18 ++++++++++++++----
 ...acheNoticeResourceTransformerParameterTests.java |  2 +-
 .../ComponentsXmlResourceTransformerTest.java       |  4 ++--
 .../resource/GroovyResourceTransformerTest.java     | 14 ++++++++------
 .../resource/ManifestResourceTransformerTest.java   |  2 +-
 .../resource/ServiceResourceTransformerTest.java    |  8 ++++----
 .../shade/resource/rule/TransformerTesterRule.java  |  2 +-
 21 files changed, 161 insertions(+), 63 deletions(-)

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 ae949a9..39eae63 100644
--- a/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java
+++ b/src/main/java/org/apache/maven/plugins/shade/DefaultShader.java
@@ -245,7 +245,8 @@ public class DefaultShader
             }
             else
             {
-                if ( !resourceTransformed( transformers, mappedName, in, shadeRequest.getRelocators() ) )
+                if ( !resourceTransformed( transformers, mappedName, in, shadeRequest.getRelocators(),
+                                           entry.getTime() ) )
                 {
                     // Avoid duplicates that aren't accounted for by the resource transformers
                     if ( resources.contains( mappedName ) )
@@ -261,11 +262,11 @@ public class DefaultShader
     }
 
     private void goThroughAllJarEntriesForManifestTransformer( ShadeRequest shadeRequest, Set<String> resources,
-                                                               ResourceTransformer manifestTransformer,
+                                                               ResourceTransformer resourceTransformer,
                                                                JarOutputStream jos )
         throws IOException
     {
-        if ( manifestTransformer != null )
+        if ( resourceTransformer != null )
         {
             for ( File jar : shadeRequest.getJars() )
             {
@@ -275,22 +276,22 @@ public class DefaultShader
                     {
                         JarEntry entry = en.nextElement();
                         String resource = entry.getName();
-                        if ( manifestTransformer.canTransformResource( resource ) )
+                        if ( resourceTransformer.canTransformResource( resource ) )
                         {
                             resources.add( resource );
                             try ( InputStream inputStream = jarFile.getInputStream( entry ) )
                             {
-                                manifestTransformer.processResource( resource, inputStream,
-                                        shadeRequest.getRelocators() );
+                                resourceTransformer.processResource( resource, inputStream,
+                                        shadeRequest.getRelocators(), entry.getTime() );
                             }
                             break;
                         }
                     }
                 }
             }
-            if ( manifestTransformer.hasTransformedResource() )
+            if ( resourceTransformer.hasTransformedResource() )
             {
-                manifestTransformer.modifyOutputStream( jos );
+                resourceTransformer.modifyOutputStream( jos );
             }
         }
     }
@@ -515,7 +516,7 @@ public class DefaultShader
     }
 
     private boolean resourceTransformed( List<ResourceTransformer> resourceTransformers, String name, InputStream is,
-                                         List<Relocator> relocators )
+                                         List<Relocator> relocators, long time )
         throws IOException
     {
         boolean resourceTransformed = false;
@@ -526,7 +527,7 @@ public class DefaultShader
             {
                 getLogger().debug( "Transforming " + name + " using " + transformer.getClass().getName() );
 
-                transformer.processResource( name, is, relocators );
+                transformer.processResource( name, is, relocators, time );
 
                 resourceTransformed = true;
 
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/ApacheLicenseResourceTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/ApacheLicenseResourceTransformer.java
index 6a0e1cf..6fd7931 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/ApacheLicenseResourceTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/ApacheLicenseResourceTransformer.java
@@ -32,7 +32,6 @@ import org.apache.maven.plugins.shade.relocation.Relocator;
 public class ApacheLicenseResourceTransformer
     implements ResourceTransformer
 {
-
     private static final String LICENSE_PATH = "META-INF/LICENSE";
 
     private static final String LICENSE_TXT_PATH = "META-INF/LICENSE.txt";
@@ -43,7 +42,7 @@ public class ApacheLicenseResourceTransformer
             || LICENSE_TXT_PATH.regionMatches( true, 0, resource, 0, LICENSE_TXT_PATH.length() );
     }
 
-    public void processResource( String resource, InputStream is, List<Relocator> relocators )
+    public void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
         throws IOException
     {
         // no op
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/ApacheNoticeResourceTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/ApacheNoticeResourceTransformer.java
index 12e5fb8..d0e25a7 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/ApacheNoticeResourceTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/ApacheNoticeResourceTransformer.java
@@ -76,6 +76,8 @@ public class ApacheNoticeResourceTransformer
      */
     String encoding;
 
+    private long time = Long.MIN_VALUE;
+
     private static final String NOTICE_PATH = "META-INF/NOTICE";
 
     private static final String NOTICE_TXT_PATH = "META-INF/NOTICE.txt";
@@ -86,7 +88,7 @@ public class ApacheNoticeResourceTransformer
 
     }
 
-    public void processResource( String resource, InputStream is, List<Relocator> relocators )
+    public void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
         throws IOException
     {
         if ( entries.isEmpty() )
@@ -191,6 +193,10 @@ public class ApacheNoticeResourceTransformer
                 currentOrg.add( sb.toString() );
             }
         }
+        if ( time > this.time )
+        {
+            this.time = time;        
+        }
     }
 
     public boolean hasTransformedResource()
@@ -201,7 +207,9 @@ public class ApacheNoticeResourceTransformer
     public void modifyOutputStream( JarOutputStream jos )
         throws IOException
     {
-        jos.putNextEntry( new JarEntry( NOTICE_PATH ) );
+        JarEntry jarEntry = new JarEntry( NOTICE_PATH );
+        jarEntry.setTime( time );
+        jos.putNextEntry( jarEntry );
 
         Writer pow;
         if ( StringUtils.isNotEmpty( encoding ) )
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/AppendingTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/AppendingTransformer.java
index 9e98259..61556eb 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/AppendingTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/AppendingTransformer.java
@@ -39,6 +39,8 @@ public class AppendingTransformer
 
     ByteArrayOutputStream data = new ByteArrayOutputStream();
 
+    private long time = Long.MIN_VALUE;
+
     public boolean canTransformResource( String r )
     {
         if ( resource != null && resource.equalsIgnoreCase( r ) )
@@ -49,11 +51,15 @@ public class AppendingTransformer
         return false;
     }
 
-    public void processResource( String resource, InputStream is, List<Relocator> relocators )
+    public void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
         throws IOException
     {
         IOUtil.copy( is, data );
         data.write( '\n' );
+        if ( time > this.time )
+        {
+            this.time = time;        
+        }
     }
 
     public boolean hasTransformedResource()
@@ -64,7 +70,9 @@ public class AppendingTransformer
     public void modifyOutputStream( JarOutputStream jos )
         throws IOException
     {
-        jos.putNextEntry( new JarEntry( resource ) );
+        JarEntry jarEntry = new JarEntry( resource );
+        jarEntry.setTime( time );
+        jos.putNextEntry( jarEntry );
 
         jos.write( data.toByteArray() );
         data.reset();
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/ComponentsXmlResourceTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/ComponentsXmlResourceTransformer.java
index 24f6936..b82b0d7 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/ComponentsXmlResourceTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/ComponentsXmlResourceTransformer.java
@@ -46,6 +46,8 @@ public class ComponentsXmlResourceTransformer
 {
     private Map<String, Xpp3Dom> components = new LinkedHashMap<>();
 
+    private long time = Long.MIN_VALUE;
+
     public static final String COMPONENTS_XML_PATH = "META-INF/plexus/components.xml";
 
     public boolean canTransformResource( String resource )
@@ -53,7 +55,7 @@ public class ComponentsXmlResourceTransformer
         return COMPONENTS_XML_PATH.equals( resource );
     }
 
-    public void processResource( String resource, InputStream is, List<Relocator> relocators )
+    public void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
         throws IOException
     {
         Xpp3Dom newDom;
@@ -126,14 +128,22 @@ public class ComponentsXmlResourceTransformer
 
             components.put( key, component );
         }
+
+        if ( time > this.time )
+        {
+            this.time = time;        
+        }
     }
 
     public void modifyOutputStream( JarOutputStream jos )
         throws IOException
     {
+        JarEntry jarEntry = new JarEntry( COMPONENTS_XML_PATH );
+        jarEntry.setTime( time );
+
         byte[] data = getTransformedResource();
 
-        jos.putNextEntry( new JarEntry( COMPONENTS_XML_PATH ) );
+        jos.putNextEntry( jarEntry );
 
         jos.write( data );
 
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/DontIncludeResourceTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/DontIncludeResourceTransformer.java
index 21cb2da..bfd1f0e 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/DontIncludeResourceTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/DontIncludeResourceTransformer.java
@@ -59,7 +59,7 @@ public class DontIncludeResourceTransformer
         return false;
     }
 
-    public void processResource( String resource, InputStream is, List<Relocator> relocators )
+    public void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
         throws IOException
     {
         // no op
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/GroovyResourceTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/GroovyResourceTransformer.java
index 754834f..f54c0cb 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/GroovyResourceTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/GroovyResourceTransformer.java
@@ -52,6 +52,8 @@ public class GroovyResourceTransformer
 
     private String extModuleVersion = "1.0";
 
+    private long time = Long.MIN_VALUE;
+
     @Override
     public boolean canTransformResource( String resource )
     {
@@ -59,7 +61,7 @@ public class GroovyResourceTransformer
     }
 
     @Override
-    public void processResource( String resource, InputStream is, List<Relocator> relocators )
+    public void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
         throws IOException
     {
         Properties out = new Properties();
@@ -77,6 +79,10 @@ public class GroovyResourceTransformer
         {
             append( staticExtensionClasses, staticExtensionClassesList );
         }
+        if ( time > this.time )
+        {
+            this.time = time;        
+        }
     }
 
     private void append( String entry, List<String> list )
@@ -99,7 +105,10 @@ public class GroovyResourceTransformer
     {
         if ( hasTransformedResource() )
         {
-            os.putNextEntry( new JarEntry( EXT_MODULE_NAME ) );
+            JarEntry jarEntry = new JarEntry( EXT_MODULE_NAME );
+            jarEntry.setTime( time );
+            os.putNextEntry( jarEntry );
+
             Properties desc = new Properties();
             desc.put( "moduleName", extModuleName );
             desc.put( "moduleVersion", extModuleVersion );
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/IncludeResourceTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/IncludeResourceTransformer.java
index b5c4581..ab360d1 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/IncludeResourceTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/IncludeResourceTransformer.java
@@ -41,15 +41,20 @@ public class IncludeResourceTransformer
 
     String resource;
 
+    private long time = Long.MIN_VALUE;
+
     public boolean canTransformResource( String r )
     {
         return false;
     }
 
-    public void processResource( String resource, InputStream is, List<Relocator> relocators )
+    public void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
         throws IOException
     {
-        // no op
+        if ( time > this.time )
+        {
+            this.time = time;        
+        }
     }
 
     public boolean hasTransformedResource()
@@ -60,9 +65,12 @@ public class IncludeResourceTransformer
     public void modifyOutputStream( JarOutputStream jos )
         throws IOException
     {
+        JarEntry jarEntry = new JarEntry( resource );
+        jarEntry.setTime( time );
+
         try ( InputStream in = new FileInputStream( file ) )
         {
-            jos.putNextEntry( new JarEntry( resource ) );
+            jos.putNextEntry( jarEntry );
             IOUtil.copy( in, jos );
         }
     }
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/ManifestResourceTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/ManifestResourceTransformer.java
index 688078c..6bf711b 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/ManifestResourceTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/ManifestResourceTransformer.java
@@ -59,7 +59,9 @@ public class ManifestResourceTransformer
     private boolean manifestDiscovered;
 
     private Manifest manifest;
-    
+
+    private long time = Long.MIN_VALUE;
+
     public void setMainClass( String mainClass )
     {
         this.mainClass = mainClass;
@@ -87,7 +89,7 @@ public class ManifestResourceTransformer
     }
 
     @Override
-    public void processResource( String resource, InputStream is, List<Relocator> relocators )
+    public void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
         throws IOException
     {
         // We just want to take the first manifest we come across as that's our project's manifest. This is the behavior
@@ -126,6 +128,11 @@ public class ManifestResourceTransformer
             }
 
             manifestDiscovered = true;
+
+            if ( time > this.time )
+            {
+                this.time = time;        
+            }
         }
     }
 
@@ -160,7 +167,9 @@ public class ManifestResourceTransformer
             }
         }
 
-        jos.putNextEntry( new JarEntry( JarFile.MANIFEST_NAME ) );
+        JarEntry jarEntry = new JarEntry( JarFile.MANIFEST_NAME );
+        jarEntry.setTime( time );
+        jos.putNextEntry( jarEntry );
         manifest.write( jos );
     }
     
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/PluginXmlResourceTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/PluginXmlResourceTransformer.java
index 4ae690d..9392b53 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/PluginXmlResourceTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/PluginXmlResourceTransformer.java
@@ -48,6 +48,8 @@ public class PluginXmlResourceTransformer
 {
     private List<Xpp3Dom> mojos = new ArrayList<>();
 
+    private long time = Long.MIN_VALUE;
+
     public static final String PLUGIN_XML_PATH = "META-INF/maven/plugin.xml";
 
     public boolean canTransformResource( String resource )
@@ -55,7 +57,7 @@ public class PluginXmlResourceTransformer
         return PLUGIN_XML_PATH.equals( resource );
     }
 
-    public void processResource( String resource, InputStream is, List<Relocator> relocators )
+    public void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
         throws IOException
     {
         Xpp3Dom newDom;
@@ -86,6 +88,11 @@ public class PluginXmlResourceTransformer
             return;
         }
 
+        if ( time > this.time )
+        {
+            this.time = time;        
+        }
+
         for ( Xpp3Dom mojo : newDom.getChild( "mojos" ).getChildren( "mojo" ) )
         {
 
@@ -134,7 +141,9 @@ public class PluginXmlResourceTransformer
     {
         byte[] data = getTransformedResource();
 
-        jos.putNextEntry( new JarEntry( PLUGIN_XML_PATH ) );
+        JarEntry jarEntry = new JarEntry( PLUGIN_XML_PATH );
+        jarEntry.setTime( time );
+        jos.putNextEntry( jarEntry );
 
         jos.write( data );
 
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/ResourceBundleAppendingTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/ResourceBundleAppendingTransformer.java
index 8214bb1..77223ee 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/ResourceBundleAppendingTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/ResourceBundleAppendingTransformer.java
@@ -38,12 +38,15 @@ import org.codehaus.plexus.util.IOUtil;
  * @author Robert Scholte
  * @since 3.0.0
  */
-public class ResourceBundleAppendingTransformer implements ResourceTransformer
+public class ResourceBundleAppendingTransformer
+    implements ResourceTransformer
 {
     private Map<String, ByteArrayOutputStream>  dataMap = new HashMap<>();
     
     private Pattern resourceBundlePattern;
-    
+
+    private long time = Long.MIN_VALUE;
+
     /**
      * the base name of the resource bundle, a fully qualified class name
      * @param basename The basename.
@@ -63,7 +66,7 @@ public class ResourceBundleAppendingTransformer implements ResourceTransformer
         return false;
     }
 
-    public void processResource( String resource, InputStream is, List<Relocator> relocators )
+    public void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
         throws IOException
     {
         ByteArrayOutputStream data = dataMap.get( resource );
@@ -75,6 +78,11 @@ public class ResourceBundleAppendingTransformer implements ResourceTransformer
         
         IOUtil.copy( is, data );
         data.write( '\n' );
+
+        if ( time > this.time )
+        {
+            this.time = time;        
+        }
     }
 
     public boolean hasTransformedResource()
@@ -87,7 +95,9 @@ public class ResourceBundleAppendingTransformer implements ResourceTransformer
     {
         for ( Map.Entry<String, ByteArrayOutputStream> dataEntry : dataMap.entrySet() )
         {
-            jos.putNextEntry( new JarEntry( dataEntry.getKey() ) );
+            JarEntry jarEntry = new JarEntry( dataEntry.getKey() );
+            jarEntry.setTime( time );
+            jos.putNextEntry( jarEntry );
 
             jos.write( dataEntry.getValue().toByteArray() );
             dataEntry.getValue().reset();
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/ResourceTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/ResourceTransformer.java
index 877f80b..bb4400a 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/ResourceTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/ResourceTransformer.java
@@ -36,9 +36,10 @@ public interface ResourceTransformer
      * @param resource The resource name
      * @param is An input stream for the resource, the implementation should *not* close this stream
      * @param relocators  A list of relocators
+     * @param time the time of the resource to process
      * @throws IOException When the IO blows up
      */
-    void processResource( String resource, InputStream is, List<Relocator> relocators )
+    void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
         throws IOException;
 
     boolean hasTransformedResource();
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/ServicesResourceTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/ServicesResourceTransformer.java
index dc0338d..da43d99 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/ServicesResourceTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/ServicesResourceTransformer.java
@@ -56,17 +56,14 @@ public class ServicesResourceTransformer
 
     private List<Relocator> relocators;
 
+    private long time = Long.MIN_VALUE;
+
     public boolean canTransformResource( String resource )
     {
-        if ( resource.startsWith( SERVICES_PATH ) )
-        {
-            return true;
-        }
-
-        return false;
+        return resource.startsWith( SERVICES_PATH );
     }
 
-    public void processResource( String resource, InputStream is, final List<Relocator> relocators )
+    public void processResource( String resource, InputStream is, final List<Relocator> relocators, long time )
         throws IOException
     {
         ServiceStream out = serviceEntries.get( resource );
@@ -99,7 +96,13 @@ public class ServicesResourceTransformer
         {
             this.relocators = relocators;
         }
+
+        if ( time > this.time )
+        {
+            this.time = time;        
+        }
     }
+
     public boolean hasTransformedResource()
     {
         return serviceEntries.size() > 0;
@@ -128,7 +131,9 @@ public class ServicesResourceTransformer
                 key = SERVICES_PATH + '/' + key;
             }
 
-            jos.putNextEntry( new JarEntry( key ) );
+            JarEntry jarEntry = new JarEntry( key );
+            jarEntry.setTime( time );
+            jos.putNextEntry( jarEntry );
 
 
             //read the content of service file for candidate classes for relocation
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/XmlAppendingTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/XmlAppendingTransformer.java
index 5e909a7..608c1a2 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/XmlAppendingTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/XmlAppendingTransformer.java
@@ -54,6 +54,8 @@ public class XmlAppendingTransformer
 
     Document doc;
 
+    private long time = Long.MIN_VALUE;
+
     public boolean canTransformResource( String r )
     {
         if ( resource != null && resource.equalsIgnoreCase( r ) )
@@ -64,7 +66,7 @@ public class XmlAppendingTransformer
         return false;
     }
 
-    public void processResource( String resource, InputStream is, List<Relocator> relocators )
+    public void processResource( String resource, InputStream is, List<Relocator> relocators, long time )
         throws IOException
     {
         Document r;
@@ -119,6 +121,11 @@ public class XmlAppendingTransformer
                 doc.getRootElement().addContent( n );
             }
         }
+
+        if ( time > this.time )
+        {
+            this.time = time;        
+        }
     }
 
     public boolean hasTransformedResource()
@@ -129,7 +136,9 @@ public class XmlAppendingTransformer
     public void modifyOutputStream( JarOutputStream jos )
         throws IOException
     {
-        jos.putNextEntry( new JarEntry( resource ) );
+        JarEntry jarEntry = new JarEntry( resource );
+        jarEntry.setTime( time );
+        jos.putNextEntry( jarEntry );
 
         new XMLOutputter( Format.getPrettyFormat() ).output( doc, jos );
 
diff --git a/src/main/java/org/apache/maven/plugins/shade/resource/properties/PropertiesTransformer.java b/src/main/java/org/apache/maven/plugins/shade/resource/properties/PropertiesTransformer.java
index e80f8f1..8040923 100644
--- a/src/main/java/org/apache/maven/plugins/shade/resource/properties/PropertiesTransformer.java
+++ b/src/main/java/org/apache/maven/plugins/shade/resource/properties/PropertiesTransformer.java
@@ -41,13 +41,15 @@ import org.apache.maven.plugins.shade.resource.properties.io.SkipPropertiesDateL
  *
  * @since 3.2.2
  */
-public class PropertiesTransformer implements ResourceTransformer
+public class PropertiesTransformer
+    implements ResourceTransformer
 {
     private String resource;
     private String alreadyMergedKey;
     private String ordinalKey;
     private int defaultOrdinal;
     private boolean reverseOrder;
+    private long time = Long.MIN_VALUE;
 
     private final List<Properties> properties = new ArrayList<>();
 
@@ -72,12 +74,17 @@ public class PropertiesTransformer implements ResourceTransformer
     }
 
     @Override
-    public void processResource( final String resource, final InputStream is, final List<Relocator> relocators )
+    public void processResource( final String resource, final InputStream is, final List<Relocator> relocators,
+                                 long time )
             throws IOException
     {
         final Properties p = new Properties();
         p.load( is );
         properties.add( p );
+        if ( time > this.time )
+        {
+            this.time = time;        
+        }
     }
 
     @Override
@@ -87,7 +94,8 @@ public class PropertiesTransformer implements ResourceTransformer
     }
 
     @Override
-    public void modifyOutputStream( final JarOutputStream os ) throws IOException
+    public void modifyOutputStream( JarOutputStream os )
+        throws IOException
     {
         if ( properties.isEmpty() )
         {
@@ -103,7 +111,9 @@ public class PropertiesTransformer implements ResourceTransformer
         {
             out.remove( alreadyMergedKey );
         }
-        os.putNextEntry( new JarEntry( resource ) );
+        JarEntry jarEntry = new JarEntry( resource );
+        jarEntry.setTime( time );
+        os.putNextEntry( jarEntry );
         final BufferedWriter writer = new SkipPropertiesDateLineWriter(
                 new OutputStreamWriter( new NoCloseOutputStream( os ), StandardCharsets.ISO_8859_1 ) );
         out.store( writer, " Merged by maven-shade-plugin (" + getClass().getName() + ")" );
diff --git a/src/test/java/org/apache/maven/plugins/shade/resource/ApacheNoticeResourceTransformerParameterTests.java b/src/test/java/org/apache/maven/plugins/shade/resource/ApacheNoticeResourceTransformerParameterTests.java
index 2db7589..7e53f54 100644
--- a/src/test/java/org/apache/maven/plugins/shade/resource/ApacheNoticeResourceTransformerParameterTests.java
+++ b/src/test/java/org/apache/maven/plugins/shade/resource/ApacheNoticeResourceTransformerParameterTests.java
@@ -95,7 +95,7 @@ public class ApacheNoticeResourceTransformerParameterTests
         {
             final ByteArrayInputStream noticeInputStream = new ByteArrayInputStream( noticeText.getBytes() );
             final List<Relocator> emptyList = Collections.emptyList();
-            subject.processResource( NOTICE_RESOURCE, noticeInputStream, emptyList );
+            subject.processResource( NOTICE_RESOURCE, noticeInputStream, emptyList, 0 );
             noticeInputStream.close();
         }
         catch ( NullPointerException e )
diff --git a/src/test/java/org/apache/maven/plugins/shade/resource/ComponentsXmlResourceTransformerTest.java b/src/test/java/org/apache/maven/plugins/shade/resource/ComponentsXmlResourceTransformerTest.java
index 45785f9..7b7f838 100644
--- a/src/test/java/org/apache/maven/plugins/shade/resource/ComponentsXmlResourceTransformerTest.java
+++ b/src/test/java/org/apache/maven/plugins/shade/resource/ComponentsXmlResourceTransformerTest.java
@@ -54,11 +54,11 @@ public class ComponentsXmlResourceTransformerTest
 
         InputStream resourceAsStream = getClass().getResourceAsStream( "/components-1.xml" );
         transformer.processResource( "components-1.xml", resourceAsStream,
-                                     Collections.<Relocator> emptyList() );
+                                     Collections.<Relocator> emptyList(), 0 );
         resourceAsStream.close();
         InputStream resourceAsStream1 = getClass().getResourceAsStream( "/components-2.xml" );
         transformer.processResource( "components-1.xml", resourceAsStream1,
-                                     Collections.<Relocator> emptyList() );
+                                     Collections.<Relocator> emptyList(), 0 );
         resourceAsStream1.close();
         final InputStream resourceAsStream2 = getClass().getResourceAsStream( "/components-expected.xml" );
         Diff diff = XMLUnit.compareXML(
diff --git a/src/test/java/org/apache/maven/plugins/shade/resource/GroovyResourceTransformerTest.java b/src/test/java/org/apache/maven/plugins/shade/resource/GroovyResourceTransformerTest.java
index b190e86..fc7137c 100644
--- a/src/test/java/org/apache/maven/plugins/shade/resource/GroovyResourceTransformerTest.java
+++ b/src/test/java/org/apache/maven/plugins/shade/resource/GroovyResourceTransformerTest.java
@@ -119,7 +119,7 @@ public class GroovyResourceTransformerTest
         transformer.setExtModuleVersion( "2.0" );
         transformer.processResource( GroovyResourceTransformer.EXT_MODULE_NAME,
                                      module( "mod1", "1.0", "some.ext", "some.staticExt" ),
-                                     Collections.<Relocator>emptyList() );
+                                     Collections.<Relocator>emptyList(), 0 );
         Properties desc = transform( transformer );
         assertEquals( "the-module-name", desc.getProperty( "moduleName" ) );
         assertEquals( "2.0", desc.getProperty( "moduleVersion" ) );
@@ -132,15 +132,17 @@ public class GroovyResourceTransformerTest
     {
         GroovyResourceTransformer transformer = new GroovyResourceTransformer();
         transformer.processResource( GroovyResourceTransformer.EXT_MODULE_NAME,
-                                     module( "mod1", "1.0", "some.ext1", null ), Collections.<Relocator>emptyList() );
+                                     module( "mod1", "1.0", "some.ext1", null ),
+                                     Collections.<Relocator>emptyList(), 0 );
         transformer.processResource( GroovyResourceTransformer.EXT_MODULE_NAME,
                                      module( "mod2", "1.0", null, "some.staticExt1" ),
-                                     Collections.<Relocator>emptyList() );
-        transformer.processResource( GroovyResourceTransformer.EXT_MODULE_NAME, module( "mod3", "1.0", "", "" ),
-                                     Collections.<Relocator>emptyList() );
+                                     Collections.<Relocator>emptyList(), 0 );
+        transformer.processResource( GroovyResourceTransformer.EXT_MODULE_NAME,
+                                     module( "mod3", "1.0", "", "" ),
+                                     Collections.<Relocator>emptyList(), 0 );
         transformer.processResource( GroovyResourceTransformer.EXT_MODULE_NAME,
                                      module( "mod4", "1.0", "some.ext2", "some.staticExt2" ),
-                                     Collections.<Relocator>emptyList() );
+                                     Collections.<Relocator>emptyList(), 0 );
         Properties desc = transform( transformer );
         assertEquals( "no-module-name", desc.getProperty( "moduleName" ) );
         assertEquals( "1.0", desc.getProperty( "moduleVersion" ) );
diff --git a/src/test/java/org/apache/maven/plugins/shade/resource/ManifestResourceTransformerTest.java b/src/test/java/org/apache/maven/plugins/shade/resource/ManifestResourceTransformerTest.java
index c1c7ff2..198d7e1 100644
--- a/src/test/java/org/apache/maven/plugins/shade/resource/ManifestResourceTransformerTest.java
+++ b/src/test/java/org/apache/maven/plugins/shade/resource/ManifestResourceTransformerTest.java
@@ -158,7 +158,7 @@ public class ManifestResourceTransformerTest
             manifest.write( mos );
         }
         transformer.processResource( JarFile.MANIFEST_NAME, new ByteArrayInputStream( mboas.toByteArray() ),
-                                     relocators );
+                                     relocators, 0 );
 
         final ByteArrayOutputStream out = new ByteArrayOutputStream();
         try ( final JarOutputStream jarOutputStream = new JarOutputStream( out ) )
diff --git a/src/test/java/org/apache/maven/plugins/shade/resource/ServiceResourceTransformerTest.java b/src/test/java/org/apache/maven/plugins/shade/resource/ServiceResourceTransformerTest.java
index fce1c71..113c325 100644
--- a/src/test/java/org/apache/maven/plugins/shade/resource/ServiceResourceTransformerTest.java
+++ b/src/test/java/org/apache/maven/plugins/shade/resource/ServiceResourceTransformerTest.java
@@ -59,7 +59,7 @@ public class ServiceResourceTransformerTest {
         String contentResourceShaded = "META-INF/services/borg.foo.something.another";
 
         ServicesResourceTransformer xformer = new ServicesResourceTransformer();
-        xformer.processResource( contentResource, contentStream, relocators );
+        xformer.processResource( contentResource, contentStream, relocators, 0 );
         contentStream.close();
 
         File tempJar = File.createTempFile("shade.", ".jar");
@@ -103,7 +103,7 @@ public class ServiceResourceTransformerTest {
         String contentResource = "META-INF/services/org.osgi.framework.launch.FrameworkFactory";
 
         ServicesResourceTransformer xformer = new ServicesResourceTransformer();
-        xformer.processResource( contentResource, contentStream, relocators );
+        xformer.processResource( contentResource, contentStream, relocators, 0 );
         contentStream.close();
 
         File tempJar = File.createTempFile("shade.", ".jar");
@@ -146,7 +146,7 @@ public class ServiceResourceTransformerTest {
         String contentResource = "META-INF/services/org.something.another";
 
         ServicesResourceTransformer xformer = new ServicesResourceTransformer();
-        xformer.processResource( contentResource, contentStream, relocators );
+        xformer.processResource( contentResource, contentStream, relocators, 0 );
         contentStream.close();
 
         content = "org.blah.Service\n";
@@ -154,7 +154,7 @@ public class ServiceResourceTransformerTest {
         contentStream = new ByteArrayInputStream( contentBytes );
         contentResource = "META-INF/services/org.something.another";
 
-        xformer.processResource( contentResource, contentStream, relocators );
+        xformer.processResource( contentResource, contentStream, relocators, 0 );
         contentStream.close();
 
         File tempJar = File.createTempFile("shade.", ".jar");
diff --git a/src/test/java/org/apache/maven/plugins/shade/resource/rule/TransformerTesterRule.java b/src/test/java/org/apache/maven/plugins/shade/resource/rule/TransformerTesterRule.java
index f520d7c..f4f7652 100644
--- a/src/test/java/org/apache/maven/plugins/shade/resource/rule/TransformerTesterRule.java
+++ b/src/test/java/org/apache/maven/plugins/shade/resource/rule/TransformerTesterRule.java
@@ -140,7 +140,7 @@ public class TransformerTesterRule implements TestRule
                 transformer.processResource(
                         resource.path(),
                         new ByteArrayInputStream( resource.content().getBytes(StandardCharsets.UTF_8) ),
-                        Collections.<Relocator>emptyList() );
+                        Collections.<Relocator>emptyList(), 0 );
             }
         }
     }