diff --git a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java index 410d9c6c57299..c1914b217828e 100644 --- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -492,4 +492,58 @@ public static boolean isKeyword(CharSequence s, SourceVersion version) { return false; } } + + /** + * {@return the latest source version that is usable under the + * runtime version argument} If the runtime version's {@linkplain + * Runtime.Version#feature() feature} is greater than the feature + * of the {@linkplain #runtimeVersion() runtime version} of the + * {@linkplain #latest() latest source version}, an {@code + * IllegalArgumentException} is thrown. + * + *
Because the source versions of the Java programming language + * have so far followed a linear progression, only the feature + * component of a runtime version is queried to determine the + * mapping to a source version. If that linearity changes in the + * future, other components of the runtime version may influence + * the result. + * + * @apiNote + * An expression to convert from a string value, for example + * {@code "17"}, to the corresponding source version, {@code + * RELEASE_17}, is: + * + *
{@code SourceVersion.valueOf(Runtime.Version.parse("17"))}
+ *
+ * @param rv runtime version to map to a source version
+ * @throws IllegalArgumentException if the feature of version
+ * argument is greater than the feature of the platform version.
+ * @since 18
+ */
+ public static SourceVersion valueOf(Runtime.Version rv) {
+ // Could also implement this as a switch where a case was
+ // added with each new release.
+ return valueOf("RELEASE_" + rv.feature());
+ }
+
+ /**
+ * {@return the least runtime version that supports this source
+ * version; otherwise {@code null}} The returned runtime version
+ * has a {@linkplain Runtime.Version#feature() feature} large
+ * enough to support this source version and has no other elements
+ * set.
+ *
+ * Source versions greater than or equal to {@link RELEASE_6}
+ * have non-{@code null} results.
+ * @since 18
+ */
+ public Runtime.Version runtimeVersion() {
+ // The javax.lang.model API was added in JDK 6; for now,
+ // limiting supported range to 6 and up.
+ if (this.compareTo(RELEASE_6) >= 0) {
+ return Runtime.Version.parse(Integer.toString(ordinal()));
+ } else {
+ return null;
+ }
+ }
}
diff --git a/test/langtools/tools/javac/processing/model/TestSourceVersion.java b/test/langtools/tools/javac/processing/model/TestSourceVersion.java
index 30d6af180b6cb..3a56bf76007fe 100644
--- a/test/langtools/tools/javac/processing/model/TestSourceVersion.java
+++ b/test/langtools/tools/javac/processing/model/TestSourceVersion.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
/*
* @test
- * @bug 7025809 8028543 6415644 8028544 8029942 8187951 8193291 8196551 8233096
+ * @bug 7025809 8028543 6415644 8028544 8029942 8187951 8193291 8196551 8233096 8275308
* @summary Test latest, latestSupported, underscore as keyword, etc.
* @author Joseph D. Darcy
* @modules java.compiler
@@ -45,6 +45,8 @@ public static void main(String... args) {
testRestrictedKeywords();
testVar();
testYield();
+ testValueOfRV();
+ testRuntimeVersion();
}
private static void testLatestSupported() {
@@ -147,4 +149,61 @@ private static void check(boolean expected,
" on " + version);
}
}
+
+ /**
+ * Test that SourceVersion.valueOf() maps a Runtime.Version to a
+ * SourceVersion properly. The SourceVersion result is only a
+ * function of the feature() component of a Runtime.Version.
+ */
+ private static void testValueOfRV() {
+ for (SourceVersion sv : SourceVersion.values()) {
+ if (sv == RELEASE_0) {
+ continue;
+ } else {
+ // Plain mapping; e.g. "17" -> RELEASE_17
+ String featureBase = Integer.toString(sv.ordinal());
+ checkValueOfResult(sv, featureBase);
+
+ // More populated runtime version, N.N
+ checkValueOfResult(sv, featureBase + "." + featureBase);
+ }
+ }
+
+ // Out of range test
+ try {
+ int latestFeature = SourceVersion.latest().runtimeVersion().feature();
+ SourceVersion.valueOf(Runtime.Version.parse(Integer.toString(latestFeature +1)));
+ throw new RuntimeException("Should not reach");
+ } catch (IllegalArgumentException iae) {
+ ; // Expected
+ }
+ }
+
+ private static void checkValueOfResult(SourceVersion expected, String versionString) {
+ Runtime.Version rv = Runtime.Version.parse(versionString);
+ SourceVersion result = SourceVersion.valueOf(rv);
+ if (result != expected) {
+ throw new RuntimeException("Unexpected result " + result +
+ " of mapping Runtime.Version " + versionString +
+ " intead of " + expected);
+ }
+ }
+
+ private static void testRuntimeVersion() {
+ for (SourceVersion sv : SourceVersion.values()) {
+ Runtime.Version result = sv.runtimeVersion();
+ if (sv.compareTo(RELEASE_6) < 0) {
+ if (result != null) {
+ throw new RuntimeException("Unexpected result non-null " + result +
+ " as runtime version of " + sv);
+ }
+ } else {
+ Runtime.Version expected = Runtime.Version.parse(Integer.toString(sv.ordinal()));
+ if (!result.equals(expected)) {
+ throw new RuntimeException("Unexpected result " + result +
+ " as runtime version of " + sv);
+ }
+ }
+ }
+ }
}