diff --git a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeMinimalJavaVersionBuildItem.java b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeMinimalJavaVersionBuildItem.java index c9a4cb8ff27e6..db90ff34076fd 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeMinimalJavaVersionBuildItem.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/builditem/nativeimage/NativeMinimalJavaVersionBuildItem.java @@ -7,17 +7,14 @@ * the native-image tool was bundled with. */ public final class NativeMinimalJavaVersionBuildItem extends MultiBuildItem { - public final int minFeature; - public final int minUpdate; + public final Runtime.Version minVersion; public final String warning; /** - * @param minFeature e.g. 17 for JDK 17.0.1 - * @param minUpdate e.g. 1 for JDK 17.0.1 + * @param minVersion e.g. 17.0.1 */ - public NativeMinimalJavaVersionBuildItem(int minFeature, int minUpdate, String warning) { - this.minFeature = minFeature; - this.minUpdate = minUpdate; + public NativeMinimalJavaVersionBuildItem(String minVersion, String warning) { + this.minVersion = Runtime.Version.parse(minVersion); this.warning = warning; } } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/GraalVM.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/GraalVM.java index 0d4d2b0da1853..d711928b67b39 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/GraalVM.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/GraalVM.java @@ -8,6 +8,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import io.quarkus.deployment.builditem.nativeimage.NativeMinimalJavaVersionBuildItem; + public final class GraalVM { // Implements version parsing after https://github.com/oracle/graal/pull/6302 @@ -52,8 +54,8 @@ static Version parse(List lines) { Matcher secondMatcher = SECOND_PATTERN.matcher(lines.get(1)); Matcher thirdMatcher = THIRD_PATTERN.matcher(lines.get(2)); if (firstMatcher.find() && secondMatcher.find() && thirdMatcher.find()) { - String javaVersion = firstMatcher.group(VNUM_GROUP); - java.lang.Runtime.Version v = null; + String javaVersion = secondMatcher.group(BUILD_INFO_GROUP); + java.lang.Runtime.Version v; try { v = java.lang.Runtime.Version.parse(javaVersion); } catch (IllegalArgumentException e) { @@ -62,8 +64,7 @@ static Version parse(List lines) { String vendorVersion = secondMatcher.group(VENDOR_VERSION_GROUP); - String buildInfo = secondMatcher.group(BUILD_INFO_GROUP); - String graalVersion = graalVersion(buildInfo, v.feature()); + String graalVersion = graalVersion(javaVersion, v.feature()); if (vendorVersion.contains("-dev")) { graalVersion = graalVersion + "-dev"; } @@ -74,7 +75,7 @@ static Version parse(List lines) { return UNKNOWN_VERSION; } return new Version(lines.stream().collect(Collectors.joining("\n")), - versNum, v.feature(), v.update(), dist); + versNum, v, dist); } else { return UNKNOWN_VERSION; } @@ -145,36 +146,37 @@ public static final class Version implements Comparable { */ private static final Pattern OLD_VERS_PATTERN = Pattern.compile( "(GraalVM|native-image)( Version)? " + VersionParseHelper.VERS_FORMAT + "(?.*?)?" + - "(\\(Java Version (?[0-9]+)(\\.(?[0-9]*)\\.(?[0-9]*))?.*)?$"); + "(\\(Java Version (?(?[0-9]+)(\\.(?[0-9]*)\\.(?[0-9]*))?.*)\\))?$"); static final Version VERSION_21_3 = new Version("GraalVM 21.3", "21.3", Distribution.GRAALVM); static final Version VERSION_21_3_0 = new Version("GraalVM 21.3.0", "21.3.0", Distribution.GRAALVM); - public static final Version VERSION_22_3_0 = new Version("GraalVM 22.3.0", "22.3.0", Distribution.GRAALVM); - public static final Version VERSION_22_2_0 = new Version("GraalVM 22.2.0", "22.2.0", Distribution.GRAALVM); - public static final Version VERSION_23_0_0 = new Version("GraalVM 23.0.0", "23.0.0", Distribution.GRAALVM); - public static final Version VERSION_23_1_0 = new Version("GraalVM 23.1.0", "23.1.0", Distribution.GRAALVM); - public static final Version VERSION_24_0_0 = new Version("GraalVM 24.0.0", "24.0.0", Distribution.GRAALVM); + public static final Version VERSION_22_3_0 = new Version("GraalVM 22.3.0", "22.3.0", "17", Distribution.GRAALVM); + public static final Version VERSION_22_2_0 = new Version("GraalVM 22.2.0", "22.2.0", "17", Distribution.GRAALVM); + public static final Version VERSION_23_0_0 = new Version("GraalVM 23.0.0", "23.0.0", "17", Distribution.GRAALVM); + public static final Version VERSION_23_1_0 = new Version("GraalVM 23.1.0", "23.1.0", "21", Distribution.GRAALVM); + public static final Version VERSION_24_0_0 = new Version("GraalVM 24.0.0", "24.0.0", "22", Distribution.GRAALVM); public static final Version MINIMUM = VERSION_22_2_0; public static final Version CURRENT = VERSION_23_1_0; - public static final int UNDEFINED = -1; final String fullVersion; - public final int javaFeatureVersion; - public final int javaUpdateVersion; + public final Runtime.Version javaVersion; final Distribution distribution; private int[] versions; private String suffix; Version(String fullVersion, String version, Distribution distro) { - this(fullVersion, version, 11, UNDEFINED, distro); + this(fullVersion, version, "11", distro); + } + + Version(String fullVersion, String version, String javaVersion, Distribution distro) { + this(fullVersion, version, Runtime.Version.parse(javaVersion), distro); } - Version(String fullVersion, String version, int javaFeatureVersion, int javaUpdateVersion, Distribution distro) { + Version(String fullVersion, String version, Runtime.Version javaVersion, Distribution distro) { this.fullVersion = fullVersion; breakdownVersion(version); - this.javaFeatureVersion = javaFeatureVersion; - this.javaUpdateVersion = javaUpdateVersion; + this.javaVersion = javaVersion; this.distribution = distro; } @@ -210,13 +212,12 @@ boolean isOlderThan(Version version) { /** * e.g. JDK 11.0.13 > 11.0.12, 17.0.1 > 11.0.13, */ - public boolean jdkVersionGreaterOrEqualTo(int feature, int update) { - return this.javaFeatureVersion > feature - || (this.javaFeatureVersion == feature && this.javaUpdateVersion >= update); + public boolean jdkVersionGreaterOrEqualTo(NativeMinimalJavaVersionBuildItem javaVersionBuildItem) { + return javaVersion.compareToIgnoreOptional(javaVersionBuildItem.minVersion) >= 0; } - boolean is(Version version) { - return this.compareTo(version) == 0; + public boolean jdkVersionGreaterOrEqualTo(String version) { + return javaVersion.compareToIgnoreOptional(Runtime.Version.parse(version)) >= 0; } @Override @@ -259,20 +260,20 @@ public static Version of(Stream output) { // GraalVM/Mandrel old, single line, version scheme: final String version = oldVersMatcher.group(VersionParseHelper.VERSION_GROUP); final String distro = oldVersMatcher.group("distro"); - // JDK: - // e.g. JDK 17.0.1, feature: 17, interim: 0 (not used here), update: 1 - final String jFeatureMatch = oldVersMatcher.group("jfeature"); - final int jFeature = jFeatureMatch == null ? // Old GraalVM versions, like 19, didn't report the Java version. - 11 : Integer.parseInt(jFeatureMatch); - final String jUpdateMatch = oldVersMatcher.group("jupdate"); - final int jUpdate = jUpdateMatch == null ? // Some JDK dev builds don't report full version string. - UNDEFINED : Integer.parseInt(jUpdateMatch); + String javaVersion = oldVersMatcher.group("javaversion"); + if (javaVersion == null) { + if (version.startsWith("19")) { + javaVersion = "11"; // Fallback to JDK 11 for GraalVM 19.x + } else { + throw new IllegalArgumentException( + "Cannot parse version from output: \n" + stringOutput); + } + } return new Version( line, version, - jFeature, - jUpdate, + Runtime.Version.parse(javaVersion), isMandrel(distro) ? Distribution.MANDREL : Distribution.GRAALVM); } } @@ -303,13 +304,12 @@ public String toString() { + getVersionAsString() + ", fullVersion=" + fullVersion + ", distribution=" + distribution + - ", javaFeatureVersion=" + javaFeatureVersion + - ", javaUpdateVersion=" + javaUpdateVersion + + ", javaVersion=" + javaVersion + '}'; } public boolean isJava17() { - return javaFeatureVersion == 17; + return javaVersion.feature() == 17; } } diff --git a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java index 217fe989049d1..c4a367b89fcee 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/NativeImageBuildStep.java @@ -299,7 +299,7 @@ public NativeImageBuildItem build(NativeConfig nativeConfig, LocalesBuildTimeCon return new NativeImageBuildItem(finalExecutablePath, new NativeImageBuildItem.GraalVMVersion(graalVMVersion.fullVersion, graalVMVersion.getVersionAsString(), - graalVMVersion.javaFeatureVersion, + graalVMVersion.javaVersion.feature(), graalVMVersion.distribution.name())); } catch (ImageGenerationFailureException e) { throw e; @@ -477,7 +477,7 @@ private RuntimeException imageGenerationFailed(int exitValue, boolean isContaine private void checkGraalVMVersion(GraalVM.Version version) { log.info("Running Quarkus native-image plugin on " + version.distribution.name() + " " + version.getVersionAsString() - + " JDK " + version.javaFeatureVersion + "." + version.javaUpdateVersion); + + " JDK " + version.javaVersion); if (version.isObsolete()) { throw new IllegalStateException("Out of date version of GraalVM detected: " + version.getVersionAsString() + "." + " Quarkus currently supports " + GraalVM.Version.CURRENT.getVersionAsString() @@ -955,17 +955,10 @@ public NativeImageInvokerInfo build() { } if (nativeMinimalJavaVersions != null && !nativeMinimalJavaVersions.isEmpty()) { - if (graalVMVersion.javaUpdateVersion == GraalVM.Version.UNDEFINED) { - log.warnf( - "Unable to parse used Java version from native-image version string `%s'. Java version checks will be skipped.", - graalVMVersion.fullVersion); - } else { - nativeMinimalJavaVersions.stream() - .filter(a -> !graalVMVersion.jdkVersionGreaterOrEqualTo(a.minFeature, a.minUpdate)) - .forEach(a -> log.warnf("Expected: Java %d, update %d, Actual: Java %d, update %d. %s", - a.minFeature, a.minUpdate, graalVMVersion.javaFeatureVersion, - graalVMVersion.javaUpdateVersion, a.warning)); - } + nativeMinimalJavaVersions.stream() + .filter(a -> !graalVMVersion.jdkVersionGreaterOrEqualTo(a)) + .forEach(a -> log.warnf("Expected: Java %s, Actual: Java %s. %s", + a.minVersion, graalVMVersion.javaVersion, a.warning)); } if (unsupportedOSes != null && !unsupportedOSes.isEmpty()) { diff --git a/core/deployment/src/test/java/io/quarkus/deployment/pkg/steps/GraalVMTest.java b/core/deployment/src/test/java/io/quarkus/deployment/pkg/steps/GraalVMTest.java index 9d251f8a48de0..7bb5a88fea6be 100644 --- a/core/deployment/src/test/java/io/quarkus/deployment/pkg/steps/GraalVMTest.java +++ b/core/deployment/src/test/java/io/quarkus/deployment/pkg/steps/GraalVMTest.java @@ -11,6 +11,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import io.quarkus.deployment.builditem.nativeimage.NativeMinimalJavaVersionBuildItem; import io.quarkus.deployment.pkg.steps.GraalVM.Distribution; import io.quarkus.deployment.pkg.steps.GraalVM.Version; @@ -100,8 +101,9 @@ public void testGraalVM21VersionParser() { + "Substrate VM GraalVM CE 21+35.1 (build 21+35, serial gc)").split("\\n"))); assertThat(graalVM21Dev.distribution.name()).isEqualTo("GRAALVM"); assertThat(graalVM21Dev.getVersionAsString()).isEqualTo("23.1"); - assertThat(graalVM21Dev.javaFeatureVersion).isEqualTo(21); - assertThat(graalVM21Dev.javaUpdateVersion).isEqualTo(0); + assertThat(graalVM21Dev.javaVersion.toString()).isEqualTo("21+35-jvmci-23.1-b15"); + assertThat(graalVM21Dev.javaVersion.feature()).isEqualTo(21); + assertThat(graalVM21Dev.javaVersion.update()).isEqualTo(0); } @Test @@ -111,8 +113,9 @@ public void testGraalVM21DevVersionParser() { "Substrate VM GraalVM CE 21-dev+35.1 (build 21+35, serial gc)").split("\\n"))); assertThat(graalVM21Dev.distribution.name()).isEqualTo("GRAALVM"); assertThat(graalVM21Dev.getVersionAsString()).isEqualTo("23.1-dev"); - assertThat(graalVM21Dev.javaFeatureVersion).isEqualTo(21); - assertThat(graalVM21Dev.javaUpdateVersion).isEqualTo(0); + assertThat(graalVM21Dev.javaVersion.toString()).isEqualTo("21+35-jvmci-23.1-b14"); + assertThat(graalVM21Dev.javaVersion.feature()).isEqualTo(21); + assertThat(graalVM21Dev.javaVersion.update()).isEqualTo(0); } @Test @@ -122,8 +125,9 @@ public void testGraalVM22DevVersionParser() { + "Substrate VM GraalVM CE 22-dev+16.1 (build 22+16, serial gc)").split("\\n"))); assertThat(graalVM22Dev.distribution.name()).isEqualTo("GRAALVM"); assertThat(graalVM22Dev.getVersionAsString()).isEqualTo("24.0-dev"); - assertThat(graalVM22Dev.javaFeatureVersion).isEqualTo(22); - assertThat(graalVM22Dev.javaUpdateVersion).isEqualTo(0); + assertThat(graalVM22Dev.javaVersion.toString()).isEqualTo("22+16-jvmci-b01"); + assertThat(graalVM22Dev.javaVersion.feature()).isEqualTo(22); + assertThat(graalVM22Dev.javaVersion.update()).isEqualTo(0); } @Test @@ -231,13 +235,13 @@ static void assertNewerThan(String version, String other) { "GraalVM 21.3.0 Java 11 CE (Java Version 11.0.13+7-jvmci-21.3-b05) |11|13|", "GraalVM 21.3.0 Java 17 CE (Java Version 17.0.1+12-jvmci-21.3-b05) |17| 1|", "GraalVM 22.0.0-dev Java 11 CE (Java Version 11.0.13+8-jvmci-22.0-b02) |11|13|", - "GraalVM Version 19.3.0 CE |11|-1|", + "GraalVM Version 19.3.0 CE |11|0|", "GraalVM Version 20.1.0.4.Final (Mandrel Distribution) (Java Version 11.0.10+9) |11|10|", "GraalVM Version 20.3.3.0-0b1 (Mandrel Distribution) (Java Version 11.0.12+7-LTS) |11|12|", "native-image 21.1.0.0-Final (Mandrel Distribution) (Java Version 11.0.11+9) |11|11|", "native-image 21.2.0.2-0b3 Mandrel Distribution (Java Version 11.0.13+8-LTS) |11|13|", "native-image 21.3.0.0-Final Mandrel Distribution (Java Version 11.0.13+8) |11|13|", - "native-image 21.3.0.0-Final Mandrel Distribution (Java Version 17-internal+0-adhoc.karm.jdk17u)|17|-1|", + "native-image 21.3.0.0-Final Mandrel Distribution (Java Version 17-internal+0-adhoc.karm.jdk17u)|17|0|", "native-image 21.3.0.0-Final Mandrel Distribution (Java Version 17.0.1+12) |17| 1|", }) // @formatter:on @@ -246,8 +250,8 @@ public void testJDKVersion(String s) { final Version v = Version.of(Stream.of(versions[0].trim())); final int expectedJdkFeature = Integer.parseInt(versions[1].trim()); final int expectedJdkUpdate = Integer.parseInt(versions[2].trim()); - Assertions.assertEquals(expectedJdkFeature, v.javaFeatureVersion, "JDK feature version mismatch."); - Assertions.assertEquals(expectedJdkUpdate, v.javaUpdateVersion, "JDK feature version mismatch."); + Assertions.assertEquals(expectedJdkFeature, v.javaVersion.feature(), "JDK feature version mismatch."); + Assertions.assertEquals(expectedJdkUpdate, v.javaVersion.update(), "JDK update version mismatch."); } @ParameterizedTest @@ -255,32 +259,44 @@ public void testJDKVersion(String s) { @ValueSource(strings = { "GraalVM 21.3.0 Java 17 CE (Java Version 17.0.1+12-jvmci-21.3-b05) |> | GraalVM 21.3.0 Java 11 CE (Java Version 11.0.13+7-jvmci-21.3-b05)", "GraalVM 22.0.0-dev Java 11 CE (Java Version 11.0.13+8-jvmci-22.0-b02) |< | GraalVM 22.0.0-dev Java 11 CE (Java Version 11.0.14+3-jvmci-22.0-b02)", + "GraalVM 22.0.0-dev Java 11 CE (Java Version 11.0.13+8-jvmci-22.0-b02) |==| GraalVM 22.0.0-dev Java 11 CE (Java Version 11.0.13+8-jvmci-22.0-b04)", + "GraalVM 22.0.0-dev Java 11 CE (Java Version 11.0.13+8-jvmci-22.0-b02) |==| GraalVM 22.0.0-dev Java 11 CE (Java Version 11.0.13+8-jvmci-21.0-b04)", "GraalVM Version 19.3.0 CE |==| GraalVM Version 19.0.0 CE", "native-image 21.3.0.0-Final Mandrel Distribution (Java Version 17-internal+0-adhoc.karm.jdk17u) |< | native-image 21.3.0.0-Final Mandrel Distribution (Java Version 17.0.1+12)", - "GraalVM 20.3.3 Java 11 (Java Version 11.0.12+6-jvmci-20.3-b20) |==| GraalVM Version 20.3.3.0-0b1 (Mandrel Distribution) (Java Version 11.0.12+7-LTS)", + "GraalVM 20.3.3 Java 11 (Java Version 11.0.12+6-jvmci-20.3-b20) |< | GraalVM Version 20.3.3.0-0b1 (Mandrel Distribution) (Java Version 11.0.12+7-LTS)", }) // @formatter:on public void testJDKVersionCompare(String s) { final String[] versions = s.split("\\|"); final Version a = Version.of(Stream.of(versions[0].trim())); final Version b = Version.of(Stream.of(versions[2].trim())); + final NativeMinimalJavaVersionBuildItem aMinimal = new NativeMinimalJavaVersionBuildItem(a.javaVersion.toString(), ""); + final NativeMinimalJavaVersionBuildItem bMinimal = new NativeMinimalJavaVersionBuildItem(b.javaVersion.toString(), ""); final String cmp = versions[1].trim(); switch (cmp) { case "<": - Assertions.assertTrue(b.jdkVersionGreaterOrEqualTo(a.javaFeatureVersion, a.javaUpdateVersion), - String.format("JDK %d.0.%d greater or equal to JDK %d.0.%d.", - b.javaFeatureVersion, b.javaUpdateVersion, a.javaFeatureVersion, a.javaUpdateVersion)); + Assertions.assertTrue(b.jdkVersionGreaterOrEqualTo(aMinimal), + String.format("JDK %s greater or equal to JDK %s.", + b.javaVersion, a.javaVersion)); + Assertions.assertFalse(a.jdkVersionGreaterOrEqualTo(bMinimal), + String.format("JDK %s smaller than JDK %s.", + a.javaVersion, b.javaVersion)); break; case ">": - Assertions.assertTrue(a.jdkVersionGreaterOrEqualTo(b.javaFeatureVersion, b.javaUpdateVersion), - String.format("JDK %d.0.%d greater or equal to JDK %d.0.%d.", - a.javaFeatureVersion, a.javaUpdateVersion, b.javaFeatureVersion, b.javaUpdateVersion)); + Assertions.assertTrue(a.jdkVersionGreaterOrEqualTo(bMinimal), + String.format("JDK %s greater or equal to JDK %s.", + a.javaVersion, b.javaVersion)); + Assertions.assertFalse(b.jdkVersionGreaterOrEqualTo(aMinimal), + String.format("JDK %s smaller than JDK %s.", + b.javaVersion, a.javaVersion)); break; case "==": - Assertions.assertTrue( - a.javaFeatureVersion == b.javaFeatureVersion && a.javaUpdateVersion == b.javaUpdateVersion, - String.format("JDK %d.0.%d equal to JDK %d.0.%d.", - a.javaFeatureVersion, a.javaUpdateVersion, b.javaFeatureVersion, b.javaUpdateVersion)); + Assertions.assertEquals(0, a.javaVersion.compareToIgnoreOptional(b.javaVersion), + String.format("JDK %s equal to JDK %s.", + b.javaVersion, a.javaVersion)); + Assertions.assertTrue(a.jdkVersionGreaterOrEqualTo(bMinimal), + String.format("JDK %s greater or equal to JDK %s.", + a.javaVersion, b.javaVersion)); break; default: throw new IllegalArgumentException("Fix the test data. Symbol " + cmp + " is unknown."); diff --git a/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java b/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java index 3a796840a990c..a3b4d06c21221 100644 --- a/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java +++ b/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java @@ -48,7 +48,7 @@ UnsupportedOSBuildItem osSupportCheck() { @BuildStep(onlyIf = NativeOrNativeSourcesBuild.class) NativeMinimalJavaVersionBuildItem nativeMinimalJavaVersionBuildItem() { - return new NativeMinimalJavaVersionBuildItem(11, 13, + return new NativeMinimalJavaVersionBuildItem("11.0.13", "AWT: Some MLib related operations, such as filter in awt.image.ConvolveOp will not work. " + "See https://bugs.openjdk.java.net/browse/JDK-8254024"); } @@ -256,7 +256,7 @@ JniRuntimeAccessBuildItem setupJava2DClasses(NativeImageRunnerBuildItem nativeIm // of baking in static libs: https://github.com/oracle/graal/issues/4921 if (v.compareTo(GraalVM.Version.VERSION_23_0_0) >= 0) { classes.add("sun.awt.X11FontManager"); - if (v.javaFeatureVersion != 19) { + if (v.javaVersion.feature() != 19) { classes.add("java.awt.GraphicsEnvironment"); classes.add("sun.awt.X11GraphicsConfig"); classes.add("sun.awt.X11GraphicsDevice"); @@ -266,7 +266,7 @@ JniRuntimeAccessBuildItem setupJava2DClasses(NativeImageRunnerBuildItem nativeIm } // Added for JDK 19+ due to: https://github.com/openjdk/jdk20/commit/9bc023220 calling FontUtilities - if (v.jdkVersionGreaterOrEqualTo(19, 0)) { + if (v.jdkVersionGreaterOrEqualTo("19")) { classes.add("sun.font.FontUtilities"); }