Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-15-SP7:GA
gradle.28016
java11-compatibility.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File java11-compatibility.patch of Package gradle.28016
--- 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 @@ -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.net.URL; import java.net.URLConnection; -public abstract class ClassLoaderUtils { - - private static final Unsafe UNSAFE; - - 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) { - 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; } @@ -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)); + 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); + } + } } } --- 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 @@ import com.google.common.annotations.VisibleForTesting; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.ArrayList; +import java.util.List; /** * An enumeration of Java versions. + * Before 9: http://www.oracle.com/technetwork/java/javase/versioning-naming-139433.html + * 9+: http://openjdk.java.net/jeps/223 */ public enum JavaVersion { - VERSION_1_1(false), VERSION_1_2(false), VERSION_1_3(false), VERSION_1_4(false), - // starting from here versions are 1_ but their official name is "Java 6", "Java 7", ... - VERSION_1_5(true), VERSION_1_6(true), VERSION_1_7(true), VERSION_1_8(true), VERSION_1_9(true), VERSION_1_10(true); + VERSION_1_1, VERSION_1_2, VERSION_1_3, VERSION_1_4, + VERSION_1_5, VERSION_1_6, VERSION_1_7, VERSION_1_8, + VERSION_1_9, VERSION_1_10, VERSION_11, VERSION_HIGHER; + // Since Java 9, version should be X instead of 1.X + // However, to keep backward compatibility, we change from 11 + private static final int FIRST_MAJOR_VERSION_ORDINAL = 10; private static JavaVersion currentJavaVersion; - private final boolean hasMajorVersion; private final String versionName; - private final String majorVersion; - JavaVersion(boolean hasMajorVersion) { - this.hasMajorVersion = hasMajorVersion; - this.versionName = name().substring("VERSION_".length()).replace('_', '.'); - this.majorVersion = name().substring(10); + JavaVersion() { + this.versionName = ordinal() >= FIRST_MAJOR_VERSION_ORDINAL ? getMajorVersion() : "1." + getMajorVersion(); } /** @@ -54,22 +55,18 @@ } String name = value.toString(); - Matcher matcher = Pattern.compile("(\\d{1,2})(\\D.+)?").matcher(name); - if (matcher.matches()) { - int index = Integer.parseInt(matcher.group(1)) - 1; - if (index > 0 && index < values().length && values()[index].hasMajorVersion) { - return values()[index]; - } - } - matcher = Pattern.compile("1\\.(\\d{1,2})(\\D.+)?").matcher(name); - if (matcher.matches()) { - int versionIdx = Integer.parseInt(matcher.group(1)) - 1; - if (versionIdx >= 0 && versionIdx < values().length) { - return values()[versionIdx]; - } + int firstNonVersionCharIndex = findFirstNonVersionCharIndex(name); + + String[] versionStrings = name.substring(0, firstNonVersionCharIndex).split("\\."); + List<Integer> versions = convertToNumber(name, versionStrings); + + if (isLegacyVersion(versions)) { + assertTrue(name, versions.get(1) > 0); + return getVersionForMajor(versions.get(1)); + } else { + return getVersionForMajor(versions.get(0)); } - throw new IllegalArgumentException(String.format("Could not determine java version from '%s'.", name)); } /** @@ -90,11 +87,7 @@ } public static JavaVersion forClassVersion(int classVersion) { - int index = classVersion - 45; //class file versions: 1.1 == 45, 1.2 == 46... - if (index >= 0 && index < values().length) { - return values()[index]; - } - throw new IllegalArgumentException(String.format("Could not determine java version from '%d'.", classVersion)); + return getVersionForMajor(classVersion - 44); //class file versions: 1.1 == 45, 1.2 == 46... } public static JavaVersion forClass(byte[] classData) { @@ -116,18 +109,22 @@ return this == VERSION_1_7; } - private boolean isJava8() { + public boolean isJava8() { return this == VERSION_1_8; } - private boolean isJava9() { + public boolean isJava9() { return this == VERSION_1_9; } - private boolean isJava10() { + public boolean isJava10() { return this == VERSION_1_10; } + public boolean isJava11() { + return this == VERSION_11; + } + public boolean isJava5Compatible() { return this.compareTo(VERSION_1_5) >= 0; } @@ -148,21 +145,69 @@ return this.compareTo(VERSION_1_9) >= 0; } - @Incubating public boolean isJava10Compatible() { return this.compareTo(VERSION_1_10) >= 0; } - @Override - public String toString() { - return getName(); + public boolean isJava11Compatible() { + return this.compareTo(VERSION_11) >= 0; } - private String getName() { + @Override + public String toString() { return versionName; } public String getMajorVersion() { - return majorVersion; + return String.valueOf(ordinal() + 1); + } + + private static JavaVersion getVersionForMajor(int major) { + return major >= values().length ? JavaVersion.VERSION_HIGHER : values()[major - 1]; + } + + private static void assertTrue(String value, boolean condition) { + if (!condition) { + throw new IllegalArgumentException("Could not determine java version from '" + value + "'."); + } + } + + private static boolean isLegacyVersion(List<Integer> versions) { + return 1 == versions.get(0) && versions.size() > 1; + } + + private static List<Integer> convertToNumber(String value, String[] versionStrs) { + List<Integer> result = new ArrayList<Integer>(); + for (String s : versionStrs) { + assertTrue(value, !isNumberStartingWithZero(s)); + try { + result.add(Integer.parseInt(s)); + } catch (NumberFormatException e) { + assertTrue(value, false); + } + } + assertTrue(value, !result.isEmpty() && result.get(0) > 0); + return result; + } + + private static boolean isNumberStartingWithZero(String number) { + return number.length() > 1 && number.startsWith("0"); + } + + private static int findFirstNonVersionCharIndex(String s) { + assertTrue(s, s.length() != 0); + + for (int i = 0; i < s.length(); ++i) { + if (!isDigitOrPeriod(s.charAt(i))) { + assertTrue(s, i != 0); + return i; + } + } + + return s.length(); + } + + private static boolean isDigitOrPeriod(char c) { + return (c >= '0' && c <= '9') || c == '.'; } } --- a/subprojects/jvm-services/src/main/java/org/gradle/internal/jvm/inspection/DefaultJvmVersionDetector.java +++ b/subprojects/jvm-services/src/main/java/org/gradle/internal/jvm/inspection/DefaultJvmVersionDetector.java @@ -62,7 +62,7 @@ public class DefaultJvmVersionDetector i try { String versionStr = reader.readLine(); while (versionStr != null) { - Matcher matcher = Pattern.compile("(?:java|openjdk) version \"(.+?)\"").matcher(versionStr); + Matcher matcher = Pattern.compile("(?:java|openjdk) version \"(.+?)\"( \\d{4}-\\d{2}-\\d{2}( LTS)?)?").matcher(versionStr); if (matcher.matches()) { return JavaVersion.toVersion(matcher.group(1)); }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor