From 500485df3a1898d4637bfa42b73e356941b4af91 Mon Sep 17 00:00:00 2001
From: Cedric Champeau <cedric@gradle.com>
Date: Thu, 13 Jul 2017 10:08:33 +0200
Subject: [PATCH] Support running Gradle on JDK 10

This commit adds support for `JavaVersion.1_10` (yes, this is awkward naming, blame versioning scheme change).
Note that there are 2 different aspects of Java 10 detection:

1. given a string representation of a version number, return the appropriate `JavaVersion` enum value
2. given the current runtime, return the appropriate `JavaVersion` enum value

This commit fixes 1, but didn't change anything in the way 2 works. In particular, 2 still uses the `java.version`
property, which is then parsed and we follow the process of 1. However, since Java 9, a new `Runtime#getVersion`
method exists, that we should use instead of relying on parsing the version number returned by `java.version`.
The reason we don't do this yet is that Gradle needs to run on older JDKs, so we cannot statically link to this
method, which involves either the use of reflection or method handles to get a hand on the result of the invocation.
Since the invocation returns a complex object (not just a `String`), we're deferring this work (PRs welcome!).
---
 .../src/main/java/org/gradle/api/JavaVersion.java  | 16 ++++++++--
 .../groovy/org/gradle/api/JavaVersionSpec.groovy   | 34 ++++++++++++++++++++--
 2 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/subprojects/base-services/src/main/java/org/gradle/api/JavaVersion.java b/subprojects/base-services/src/main/java/org/gradle/api/JavaVersion.java
index 3b9a7280c14..4a2195a5b0b 100644
--- a/subprojects/base-services/src/main/java/org/gradle/api/JavaVersion.java
+++ b/subprojects/base-services/src/main/java/org/gradle/api/JavaVersion.java
@@ -24,7 +24,9 @@
  * An enumeration of Java versions.
  */
 public enum JavaVersion {
-    VERSION_1_1(false), VERSION_1_2(false), VERSION_1_3(false), VERSION_1_4(false), VERSION_1_5(true), VERSION_1_6(true), VERSION_1_7(true), VERSION_1_8(true), VERSION_1_9(true);
+    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);
     private static JavaVersion currentJavaVersion;
     private final boolean hasMajorVersion;
     private final String versionName;
@@ -52,7 +54,7 @@ public static JavaVersion toVersion(Object value) throws IllegalArgumentExceptio
         }
 
         String name = value.toString();
-        Matcher matcher = Pattern.compile("(\\d)(-.+)?").matcher(name);
+        Matcher matcher = Pattern.compile("(\\d{1,2})(-.+)?").matcher(name);
         if (matcher.matches()) {
             int index = Integer.parseInt(matcher.group(1)) - 1;
             if (index < values().length && values()[index].hasMajorVersion) {
@@ -60,7 +62,7 @@ public static JavaVersion toVersion(Object value) throws IllegalArgumentExceptio
             }
         }
 
-        matcher = Pattern.compile("1\\.(\\d)(\\D.+)?").matcher(name);
+        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) {
@@ -122,6 +124,10 @@ private boolean isJava9() {
         return this == VERSION_1_9;
     }
 
+    private boolean isJava10() {
+        return this == VERSION_1_10;
+    }
+
     public boolean isJava5Compatible() {
         return this.compareTo(VERSION_1_5) >= 0;
     }
@@ -142,6 +148,10 @@ public boolean isJava9Compatible() {
         return this.compareTo(VERSION_1_9) >= 0;
     }
 
+    public boolean isJava10Compatible() {
+        return this.compareTo(VERSION_1_10) >= 0;
+    }
+
     @Override
     public String toString() {
         return getName();
diff --git a/subprojects/base-services/src/test/groovy/org/gradle/api/JavaVersionSpec.groovy b/subprojects/base-services/src/test/groovy/org/gradle/api/JavaVersionSpec.groovy
index fab8be67274..75459ed3f06 100644
--- a/subprojects/base-services/src/test/groovy/org/gradle/api/JavaVersionSpec.groovy
+++ b/subprojects/base-services/src/test/groovy/org/gradle/api/JavaVersionSpec.groovy
@@ -41,6 +41,7 @@ public class JavaVersionSpec extends Specification {
         JavaVersion.VERSION_1_7.toString() == "1.7"
         JavaVersion.VERSION_1_8.toString() == "1.8"
         JavaVersion.VERSION_1_9.toString() == "1.9"
+        JavaVersion.VERSION_1_10.toString() == "1.10"
     }
 
     def convertsStringToVersion() {
@@ -57,10 +58,13 @@ public class JavaVersionSpec extends Specification {
         JavaVersion.toVersion("7") == JavaVersion.VERSION_1_7
         JavaVersion.toVersion("8") == JavaVersion.VERSION_1_8
         JavaVersion.toVersion("9") == JavaVersion.VERSION_1_9
+        JavaVersion.toVersion("10") == JavaVersion.VERSION_1_10
 
         JavaVersion.toVersion("1.9.0-internal") == JavaVersion.VERSION_1_9
         JavaVersion.toVersion("1.9.0-ea") == JavaVersion.VERSION_1_9
         JavaVersion.toVersion("9-ea") == JavaVersion.VERSION_1_9
+
+        JavaVersion.toVersion("10-ea") == JavaVersion.VERSION_1_10
     }
 
     def convertClassVersionToJavaVersion() {
@@ -74,6 +78,7 @@ public class JavaVersionSpec extends Specification {
         JavaVersion.forClassVersion(51) == JavaVersion.VERSION_1_7
         JavaVersion.forClassVersion(52) == JavaVersion.VERSION_1_8
         JavaVersion.forClassVersion(53) == JavaVersion.VERSION_1_9
+        JavaVersion.forClassVersion(54) == JavaVersion.VERSION_1_10
     }
 
     def failsToConvertStringToVersionForUnknownVersion() {
@@ -81,7 +86,6 @@ public class JavaVersionSpec extends Specification {
         conversionFails("1");
         conversionFails("2");
 
-        conversionFails("10");
         conversionFails("17");
 
         conversionFails("a");
@@ -91,7 +95,6 @@ public class JavaVersionSpec extends Specification {
 
         conversionFails("0.1");
         conversionFails("1.54");
-        conversionFails("1.10");
         conversionFails("2.0");
         conversionFails("1_4");
         conversionFails("8.1");
@@ -100,7 +103,7 @@ public class JavaVersionSpec extends Specification {
         conversionFails("10.1.2");
 
         conversionFails("9-");
-        conversionFails("10-ea");
+        conversionFails("11-ea");
     }
 
     def convertsVersionToVersion() {
@@ -118,6 +121,8 @@ public class JavaVersionSpec extends Specification {
         JavaVersion.toVersion(1.7) == JavaVersion.VERSION_1_7
         JavaVersion.toVersion(1.8) == JavaVersion.VERSION_1_8
         JavaVersion.toVersion(1.9) == JavaVersion.VERSION_1_9
+        JavaVersion.toVersion(9) == JavaVersion.VERSION_1_9
+        JavaVersion.toVersion(10) == JavaVersion.VERSION_1_10
     }
 
     def failsToConvertNumberToVersionForUnknownVersion() {
@@ -233,4 +238,27 @@ public class JavaVersionSpec extends Specification {
         where:
         javaVersion << ['1.9', '9-ea']
     }
+
+    def "uses system property to determine if compatible with Java 10"() {
+        System.properties['java.version'] = javaVersion
+
+        expect:
+        !JavaVersion.current().java5
+        !JavaVersion.current().java6
+        !JavaVersion.current().java7
+        !JavaVersion.current().java8
+        !JavaVersion.current().java9
+        JavaVersion.current().java10
+
+        and:
+        JavaVersion.current().java5Compatible
+        JavaVersion.current().java6Compatible
+        JavaVersion.current().java7Compatible
+        JavaVersion.current().java8Compatible
+        JavaVersion.current().java9Compatible
+        JavaVersion.current().java10Compatible
+
+        where:
+        javaVersion << ['1.10', '10-ea']
+    }
 }
