[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#931012: unblock: gradle/4.4.1-6



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock

Hi,

I'd like to request gradle/4.4.1-6 to be unblocked. When fixing the gradle
package to work with OpenJDK 11 we mistakenly broke the compatibility with
OpenJDK 8 (#925225). Even if Buster ships only with OpenJDK 11 we cared to
preserve the compatibility of the Java build tools in Debian (Ant and Maven)
with OpenJDK 8 since it's still the most popular JDK (a recent survey
conducted by Jetbrains showed that 80% of the Java developers were still
using Java 8, and only 20% have adopted Java 11). We can expect the users
to be disappointed if the gradle package requires OpenJDK 11 or higher.

Ubuntu fixed the OpenJDK 8 compatibility 3 months ago and forwarded the
patch to Debian (the patch was backported from upstream). I've uploaded
the fix to unstable as gradle/4.4.1-6 and I've verified that the main
packages using Gradle are still building fine (openjfx, libspring-java,
gradle itself and a few others).

Thank you,

Emmanuel Bourg

unblock gradle/4.4.1-6
diff -Nru gradle-4.4.1/debian/changelog gradle-4.4.1/debian/changelog
--- gradle-4.4.1/debian/changelog	2019-02-26 20:02:13.000000000 +0100
+++ gradle-4.4.1/debian/changelog	2019-06-22 00:52:47.000000000 +0200
@@ -1,3 +1,17 @@
+gradle (4.4.1-6) unstable; urgency=medium
+
+  [ Tiago Stürmer Daitx ]
+  * Fix OpenJDK 8 compatibility: (Closes: #925225)
+    - debian/patches/java8-compatibility.patch: cast ByteBuffer to Buffer
+      in org.gradle.internal.hash.Hashing to prevent NoSuchMethodError
+      exception.
+    - debian/patches/java11-compatibility.patch: copy upstream commit for
+      "Use Lookup to invoke defineClass on Java 9+ (#4976)" instead using
+      the previous partial backport to enable both OpenJDK 8 and 11 support.
+  * debian/control: revert gradle Depends back to java 8
+
+ -- Emmanuel Bourg <ebourg@apache.org>  Sat, 22 Jun 2019 00:52:47 +0200
+
 gradle (4.4.1-5) unstable; urgency=medium
 
   * Team upload.
diff -Nru gradle-4.4.1/debian/control gradle-4.4.1/debian/control
--- gradle-4.4.1/debian/control	2019-02-26 20:02:13.000000000 +0100
+++ gradle-4.4.1/debian/control	2019-06-22 00:49:27.000000000 +0200
@@ -76,7 +76,7 @@
 
 Package: gradle
 Architecture: all
-Depends: default-jre-headless (>= 2:1.9) | java9-runtime-headless,
+Depends: default-jre-headless (>= 2:1.8) | java8-runtime-headless,
          libgradle-core-java (>= ${binary:Version}),
          libgradle-plugins-java (>= ${binary:Version}),
          ${misc:Depends}
diff -Nru gradle-4.4.1/debian/patches/java11-compatibility.patch gradle-4.4.1/debian/patches/java11-compatibility.patch
--- gradle-4.4.1/debian/patches/java11-compatibility.patch	2019-02-26 20:02:13.000000000 +0100
+++ gradle-4.4.1/debian/patches/java11-compatibility.patch	2019-06-22 00:50:07.000000000 +0200
@@ -4,51 +4,238 @@
                   https://github.com/gradle/gradle/commit/3db6e256987053171178aa96a0ef46caedc8d1a4
 --- a/subprojects/base-services/src/main/java/org/gradle/internal/classloader/ClassLoaderUtils.java
 +++ b/subprojects/base-services/src/main/java/org/gradle/internal/classloader/ClassLoaderUtils.java
-@@ -24,6 +24,9 @@
+@@ -15,51 +15,41 @@
+  */
+ package org.gradle.internal.classloader;
+ 
++import org.gradle.api.JavaVersion;
+ import org.gradle.internal.Cast;
+ import org.gradle.internal.UncheckedException;
+ import org.gradle.internal.concurrent.CompositeStoppable;
+ import org.gradle.internal.reflect.JavaMethod;
+-import org.gradle.internal.reflect.JavaReflectionUtil;
+-import sun.misc.Unsafe;
  
  import javax.annotation.Nullable;
  import java.io.IOException;
+-import java.lang.reflect.Field;
+-import java.net.MalformedURLException;
 +import java.lang.invoke.MethodHandle;
 +import java.lang.invoke.MethodHandles;
 +import java.lang.invoke.MethodType;
- import java.lang.reflect.Field;
- import java.net.MalformedURLException;
  import java.net.URL;
-@@ -31,16 +34,15 @@
- 
- public abstract class ClassLoaderUtils {
+ import java.net.URLConnection;
  
+-public abstract class ClassLoaderUtils {
+-
 -    private static final Unsafe UNSAFE;
-+    private static MethodHandle defineClassMethodHandle;
- 
-     static {
-         try {
+-
+-    static {
+-        try {
 -            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
 -            theUnsafe.setAccessible(true);
 -            UNSAFE = (Unsafe) theUnsafe.get(null);
 -        } catch (NoSuchFieldException e) {
 -            throw new RuntimeException(e);
 -        } catch (IllegalAccessException e) {
-+            MethodHandles.Lookup baseLookup = MethodHandles.lookup();
-+            MethodType defineClassMethodType = MethodType.methodType(Class.class, new Class[]{String.class, byte[].class, int.class, int.class});
-+            MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(ClassLoader.class, baseLookup);
-+            defineClassMethodHandle = lookup.findVirtual(ClassLoader.class, "defineClass", defineClassMethodType);
-+        } catch (Throwable e) {
-             throw new RuntimeException(e);
+-            throw new RuntimeException(e);
+-        }
+-    }
++import static org.gradle.internal.reflect.JavaReflectionUtil.method;
++import static org.gradle.internal.reflect.JavaReflectionUtil.staticMethod;
+ 
++public abstract class ClassLoaderUtils {
++    private static final ClassDefiner CLASS_DEFINER;
+     private static final JavaMethod<ClassLoader, Package[]> GET_PACKAGES_METHOD;
+     private static final JavaMethod<ClassLoader, Package> GET_PACKAGE_METHOD;
+ 
+     static {
++        CLASS_DEFINER = JavaVersion.current().isJava9Compatible() ? new LookupClassDefiner() : new ReflectionClassDefiner();
+         GET_PACKAGES_METHOD = getMethodWithFallback(Package[].class, new Class[0], "getDefinedPackages", "getPackages");
+-        GET_PACKAGE_METHOD = getMethodWithFallback(Package.class, new Class[] {String.class}, "getDefinedPackage", "getPackage");
++        GET_PACKAGE_METHOD = getMethodWithFallback(Package.class, new Class[]{String.class}, "getDefinedPackage", "getPackage");
+     }
+ 
+     private static <T> JavaMethod<ClassLoader, T> getMethodWithFallback(Class<T> clazz, Class<?>[] params, String firstChoice, String fallback) {
+         JavaMethod<ClassLoader, T> method;
+         try {
+-            method = JavaReflectionUtil.method(ClassLoader.class, clazz, firstChoice, params);
++            method = method(ClassLoader.class, clazz, firstChoice, params);
+         } catch (Throwable e) {
+             // We must not be on Java 9 where the getDefinedPackages() method exists. Fall back to getPackages()
+-            method = JavaReflectionUtil.method(ClassLoader.class, clazz, fallback, params);
++            method = method(ClassLoader.class, clazz, fallback, params);
          }
+         return method;
      }
-@@ -101,6 +103,10 @@
+@@ -85,8 +75,6 @@ public static void disableUrlConnectionCaching() {
+             URL url = new URL("jar:file://valid_jar_url_syntax.jar!/");
+             URLConnection urlConnection = url.openConnection();
+             urlConnection.setDefaultUseCaches(false);
+-        } catch (MalformedURLException e) {
+-            throw UncheckedException.throwAsUncheckedException(e);
+         } catch (IOException e) {
+             throw UncheckedException.throwAsUncheckedException(e);
+         }
+@@ -101,6 +89,63 @@ public static void disableUrlConnectionCaching() {
      }
  
      public static <T> Class<T> define(ClassLoader targetClassLoader, String className, byte[] clazzBytes) {
 -        return Cast.uncheckedCast(UNSAFE.defineClass(className, clazzBytes, 0, clazzBytes.length, targetClassLoader, null));
-+        try {
-+            return (Class) defineClassMethodHandle.bindTo(targetClassLoader).invokeWithArguments(className, clazzBytes, 0, clazzBytes.length);
-+        } catch (Throwable e) {
-+            throw new RuntimeException(e);
++        return CLASS_DEFINER.defineClass(targetClassLoader, className, clazzBytes);
++    }
++
++    private interface ClassDefiner {
++        <T> Class<T> defineClass(ClassLoader classLoader, String className, byte[] classBytes);
++    }
++
++    private static class ReflectionClassDefiner implements ClassDefiner {
++        private final JavaMethod<ClassLoader, Class> defineClassMethod;
++
++        private ReflectionClassDefiner() {
++            defineClassMethod = method(ClassLoader.class, Class.class, "defineClass", String.class, byte[].class, int.class, int.class);
++        }
++
++        @Override
++        public <T> Class<T> defineClass(ClassLoader classLoader, String className, byte[] classBytes) {
++            return Cast.uncheckedCast(defineClassMethod.invoke(classLoader, className, classBytes, 0, classBytes.length));
++        }
++    }
++
++    private static class LookupClassDefiner implements ClassDefiner {
++        private final Class methodHandlesLookupClass;
++        private final JavaMethod methodHandlesLookup;
++        private final JavaMethod methodHandlesPrivateLookupIn;
++        private final JavaMethod lookupFindVirtual;
++        private final MethodType defineClassMethodType;
++
++        private LookupClassDefiner() {
++            try {
++                methodHandlesLookupClass = Class.forName("java.lang.invoke.MethodHandles$Lookup");
++            } catch (ClassNotFoundException e) {
++                throw new RuntimeException(e);
++            }
++            methodHandlesLookup = staticMethod(MethodHandles.class, methodHandlesLookupClass, "lookup");
++            methodHandlesPrivateLookupIn = staticMethod(MethodHandles.class, methodHandlesLookupClass, "privateLookupIn", Class.class, methodHandlesLookupClass);
++            lookupFindVirtual = method(methodHandlesLookupClass, MethodHandle.class, "findVirtual", Class.class, String.class, MethodType.class);
++            defineClassMethodType = MethodType.methodType(Class.class, new Class[]{String.class, byte[].class, int.class, int.class});
++        }
++
++        /*
++            This method is equivalent to the following code but use reflection to compile on Java 7:
++
++            MethodHandles.Lookup baseLookup = MethodHandles.lookup();
++            MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(ClassLoader.class, baseLookup);
++            MethodHandle defineClassMethodHandle = lookup.findVirtual(ClassLoader.class, "defineClass", defineClassMethodType);
++            handle.bindTo(classLoader).invokeWithArguments(className, classBytes, 0, classBytes.length));
++         */
++        @Override
++        public <T> Class<T> defineClass(ClassLoader classLoader, String className, byte[] classBytes) {
++            Object baseLookup = methodHandlesLookup.invoke(null);
++            Object lookup = methodHandlesPrivateLookupIn.invoke(null, ClassLoader.class, baseLookup);
++            MethodHandle defineClassMethodHandle = (MethodHandle) lookupFindVirtual.invoke(lookup, ClassLoader.class, "defineClass", defineClassMethodType);
++            try {
++                return Cast.uncheckedCast(defineClassMethodHandle.bindTo(classLoader).invokeWithArguments(className, classBytes, 0, classBytes.length));
++            } catch (Throwable throwable) {
++                throw new RuntimeException(throwable);
++            }
 +        }
      }
  }
+diff --git a/subprojects/core/src/main/java/org/gradle/process/internal/worker/child/WorkerProcessClassPathProvider.java b/subprojects/core/src/main/java/org/gradle/process/internal/worker/child/WorkerProcessClassPathProvider.java
+index 9a7fd911c78f..c1324a04fef5 100644
+--- a/subprojects/core/src/main/java/org/gradle/process/internal/worker/child/WorkerProcessClassPathProvider.java
++++ b/subprojects/core/src/main/java/org/gradle/process/internal/worker/child/WorkerProcessClassPathProvider.java
+@@ -18,6 +18,7 @@
+ 
+ import org.gradle.api.Action;
+ import org.gradle.api.GradleException;
++import org.gradle.api.JavaVersion;
+ import org.gradle.api.internal.ClassPathProvider;
+ import org.gradle.api.specs.Spec;
+ import org.gradle.cache.CacheRepository;
+@@ -57,7 +58,9 @@
+ import java.io.InputStream;
+ import java.net.URL;
+ import java.util.Arrays;
++import java.util.HashSet;
+ import java.util.List;
++import java.util.Set;
+ import java.util.zip.ZipEntry;
+ import java.util.zip.ZipOutputStream;
+ 
+@@ -116,32 +119,9 @@ public void execute(PersistentCache cache) {
+             try {
+                 File jarFile = jarFile(cache);
+                 LOGGER.debug("Generating worker process classes to {}.", jarFile);
+-
+-                // TODO - calculate this list of classes dynamically
+-                List<Class<?>> classes = Arrays.asList(
+-                        GradleWorkerMain.class,
+-                        BootstrapSecurityManager.class,
+-                        EncodedStream.EncodedInput.class,
+-                        ClassLoaderUtils.class,
+-                        FilteringClassLoader.class,
+-                        FilteringClassLoader.Spec.class,
+-                        ClassLoaderHierarchy.class,
+-                        ClassLoaderVisitor.class,
+-                        ClassLoaderSpec.class,
+-                        SystemClassLoaderSpec.class,
+-                        JavaReflectionUtil.class,
+-                        JavaMethod.class,
+-                        GradleException.class,
+-                        NoSuchPropertyException.class,
+-                        NoSuchMethodException.class,
+-                        UncheckedException.class,
+-                        PropertyAccessor.class,
+-                        PropertyMutator.class,
+-                        Factory.class,
+-                        Spec.class);
+                 ZipOutputStream outputStream = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(jarFile)));
+                 try {
+-                    for (Class<?> classToMap : classes) {
++                    for (Class<?> classToMap : getClassesForWorkerJar()) {
+                         remapClass(classToMap, outputStream);
+                     }
+                 } finally {
+@@ -152,6 +132,37 @@ public void execute(PersistentCache cache) {
+             }
+         }
+ 
++        private Set<Class<?>> getClassesForWorkerJar() {
++            // TODO - calculate this list of classes dynamically
++            List<Class<?>> classes = Arrays.asList(
++                GradleWorkerMain.class,
++                BootstrapSecurityManager.class,
++                EncodedStream.EncodedInput.class,
++                ClassLoaderUtils.class,
++                FilteringClassLoader.class,
++                ClassLoaderHierarchy.class,
++                ClassLoaderVisitor.class,
++                ClassLoaderSpec.class,
++                SystemClassLoaderSpec.class,
++                JavaReflectionUtil.class,
++                JavaMethod.class,
++                GradleException.class,
++                NoSuchPropertyException.class,
++                NoSuchMethodException.class,
++                UncheckedException.class,
++                PropertyAccessor.class,
++                PropertyMutator.class,
++                Factory.class,
++                Spec.class,
++                JavaVersion.class);
++            Set<Class<?>> result = new HashSet<Class<?>>(classes);
++            for (Class<?> klass : classes) {
++                result.addAll(Arrays.asList(klass.getDeclaredClasses()));
++            }
++
++            return result;
++        }
++
+         private void remapClass(Class<?> classToMap, ZipOutputStream jar) throws IOException {
+             String internalName = Type.getInternalName(classToMap);
+             String resourceName = internalName.concat(".class");
 --- a/subprojects/base-services/src/main/java/org/gradle/api/JavaVersion.java
 +++ b/subprojects/base-services/src/main/java/org/gradle/api/JavaVersion.java
 @@ -17,25 +17,26 @@
diff -Nru gradle-4.4.1/debian/patches/java8-compatibility.patch gradle-4.4.1/debian/patches/java8-compatibility.patch
--- gradle-4.4.1/debian/patches/java8-compatibility.patch	2019-02-26 20:02:13.000000000 +0100
+++ gradle-4.4.1/debian/patches/java8-compatibility.patch	2019-06-22 00:48:57.000000000 +0200
@@ -74,3 +74,14 @@
          return charbuffer;
      }
  
+--- a/subprojects/base-services/src/main/java/org/gradle/internal/hash/Hashing.java
++++ b/subprojects/base-services/src/main/java/org/gradle/internal/hash/Hashing.java
+@@ -158,7 +158,7 @@ public class Hashing {
+         private void update(int length) {
+             checkNotDone();
+             digest.update(buffer.array(), 0, length);
+-            buffer.clear();
++            ((java.nio.Buffer) buffer).clear();
+         }
+ 
+         @Override

Reply to: