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: