Blob Blame History Raw
From df720cdeb86e671ac336d337dfedda1cf2d1f711 Mon Sep 17 00:00:00 2001
From: Mikolaj Izdebski <mizdebsk@redhat.com>
Date: Wed, 28 Oct 2015 13:08:23 +0100
Subject: [PATCH 2/5] Add duplicated ZIP entry hack for OpenJDK

---
 .../xmvn/tools/install/impl/JarUtils.java          | 29 ++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/JarUtils.java b/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/JarUtils.java
index 5dd09ea..ae2a5a6 100644
--- a/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/JarUtils.java
+++ b/xmvn-tools/xmvn-install/src/main/java/org/fedoraproject/xmvn/tools/install/impl/JarUtils.java
@@ -16,8 +16,10 @@
 package org.fedoraproject.xmvn.tools.install.impl;
 
 import java.io.IOException;
+import java.lang.reflect.Field;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.Collection;
 import java.util.jar.Attributes;
 import java.util.jar.JarEntry;
 import java.util.jar.JarInputStream;
@@ -25,6 +27,7 @@ import java.util.jar.JarOutputStream;
 import java.util.jar.Manifest;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
 
 import org.objectweb.asm.ClassReader;
 import org.objectweb.asm.ClassVisitor;
@@ -165,6 +168,31 @@ class JarUtils
     }
 
     /**
+     * OpenJDK has a sanity check that prevents adding duplicate entries to ZIP streams. The problem is that some of
+     * JARs we try to inject manifests to (especially the ones created by Gradle) already contain duplicate entries, so
+     * manifest injection would always fail for them with "ZipException: duplicate entry".
+     * <p>
+     * This function tries to work around this OpenJDK sanity check, effectively allowing creating ZIP files with
+     * duplicated entries. It should be called on particular ZIP output stream before adding each duplicate entry.
+     * 
+     * @param zipOutputStream ZIP stream to hack
+     */
+    private static void openJdkAvoidDuplicateEntryHack( ZipOutputStream zipOutputStream )
+    {
+        try
+        {
+            Field namesField = ZipOutputStream.class.getDeclaredField( "names" );
+            namesField.setAccessible( true );
+            Collection<?> names = (Collection<?>) namesField.get( zipOutputStream );
+            names.clear();
+        }
+        catch ( ReflectiveOperationException e )
+        {
+            // This hack relies on OpenJDK internals and therefore is not ugarranteed to work. Ignore failures.
+        }
+    }
+
+    /**
      * Inject artifact coordinates into manifest of specified JAR (or WAR, EAR, ...) file. The file is modified
      * in-place.
      * 
@@ -200,6 +228,7 @@ class JarUtils
                 JarEntry entry;
                 while ( ( entry = jis.getNextJarEntry() ) != null )
                 {
+                    openJdkAvoidDuplicateEntryHack( jos );
                     jos.putNextEntry( entry );
 
                     int sz;
-- 
2.7.4