diff --git a/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java b/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java index 70eb921a12454..60021db386e1f 100644 --- a/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java +++ b/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java @@ -25,23 +25,43 @@ package java.lang.reflect; +import java.lang.classfile.ClassFile; + +import jdk.internal.javac.PreviewFeature; + /** - * Class file format versions of the Java virtual machine. - * - * See the appropriate edition of The Java Virtual Machine - * Specification for information about a particular class file - * format version. - * - *
Note that additional class file format version constants will be - * added to model future releases of the Java Virtual Machine - * Specification. + * Class file format versions of the Java virtual machine. Each class file + * format has a particular set of VM features. See The Java Virtual + * Machine Specification, Section {@jvms 4.1} for the list of class + * file format versions supported by the current release. The JVMS also + * describes, for each VM feature, the versions that support that feature, if + * it is not supported by all class file format versions. + *
+ * Future editions of the JVMS may retroactively loosen restrictions imposed on + * a class file format version; for example, the {@linkplain #RELEASE_1 version + * for 1.1} is later extended to allow invocations of static methods in + * interfaces, introduced by Java SE 8; such a class file might not run on the + * release that introduced its format version. For each Java SE release, see + * the corresponding edition of the JVMS for requirements on class files to run + * on that Java SE release. + *
+ * Additional class file format version constants will be added to model future + * class file formats defined by future releases of the JVMS. + *
+ * A special constant, {@link #CURRENT_PREVIEW}, representing the + * preview VM features of the current Java SE release, is not a class file + * format version, but can be viewed as a future class file format version. + * Each of the preview VM features is described by a separate document on the + * site that hosts the corresponding edition of JVMS. Unlike the features in + * class file format versions, the preview VM features are only supported when + * preview features are enabled, and are not {@linkplain #isSupported() + * supported by future releases}. * * @apiNote - * The complete version used in a class file includes a major version - * and a minor version; this enum only models the major version. A - * Java virtual machine implementation is required to support a range - * of major versions; see the corresponding edition of the The - * Java Virtual Machine Specification for details. + * Each class file format version corresponds to exactly one major version and + * one or more minor versions. Each major version corresponds to one class file + * format version, except for {@value ClassFile#JAVA_1_VERSION}, which {@link + * #RELEASE_0} and {@link #RELEASE_1} both correspond to. * * @since 20 * @see System#getProperties System property {@code java.class.version} @@ -50,8 +70,8 @@ @SuppressWarnings("doclint:reference") // cross-module links public enum ClassFileFormatVersion { /* - * Summary of class file format evolution; previews are listed for - * convenience, but they are not modeled by this enum. + * Summary of class file format evolution; previews listed for convenience + * * 1.1: InnerClasses, Synthetic, Deprecated attributes * 1.2: ACC_STRICT modifier * 1.3: no changes @@ -89,6 +109,7 @@ public enum ClassFileFormatVersion { * 22: no changes * 23: no changes * 24: no changes + * 25: no changes */ /** @@ -316,11 +337,10 @@ public enum ClassFileFormatVersion { * The version introduced by the Java Platform, Standard Edition * 21. * - * @since 21 - * * @see * The Java Virtual Machine Specification, Java SE 21 Edition + * @since 21 */ RELEASE_21(65), @@ -328,11 +348,10 @@ public enum ClassFileFormatVersion { * The version introduced by the Java Platform, Standard Edition * 22. * - * @since 22 - * * @see * The Java Virtual Machine Specification, Java SE 22 Edition + * @since 22 */ RELEASE_22(66), @@ -340,11 +359,10 @@ public enum ClassFileFormatVersion { * The version introduced by the Java Platform, Standard Edition * 23. * - * @since 23 - * * @see * The Java Virtual Machine Specification, Java SE 23 Edition + * @since 23 */ RELEASE_23(67), @@ -352,11 +370,10 @@ public enum ClassFileFormatVersion { * The version introduced by the Java Platform, Standard Edition * 24. * - * @since 24 - * * @see * The Java Virtual Machine Specification, Java SE 24 Edition + * @since 24 */ RELEASE_24(68), @@ -364,17 +381,53 @@ public enum ClassFileFormatVersion { * The version introduced by the Java Platform, Standard Edition * 25. * - * @since 25 - * * @see * The Java Virtual Machine Specification, Java SE 25 Edition + * @since 25 */ RELEASE_25(69), - ; // Reduce code churn when appending new constants - // Note to maintainers: when adding constants for newer releases, - // the implementation of latest() must be updated too. + // Note to maintainers: Add new constants right above. + // The implementation of latest() must be updated too. + /** + * An enum constant representing all preview VM features of the {@linkplain + * #latest() current Java SE release} in addition to those of the latest + * class file format version. Unlike VM features associated to enum + * constants representing a class file format version, VM features + * associated to this enum constant are not {@linkplain #isSupported() + * supported} by later Java SE releases. + *
+ * {@code class} files using any preview feature from the current Java SE + * release uses the same major version from that release, but uses the minor + * version {@value %04x ClassFile#PREVIEW_MINOR_VERSION} with all bits set + * to {@code 1}. This Java Runtime Environment does not load any {@code + * class} file using preview features from other Java SE releases. + * + * @apiNote + * While this is not a class file format version, it can be considered as + * the class file format version of an arbitrary future Java SE release. + * Programmers should test their programs with preview features enabled to + * ensure the program is compatible with future Java SE releases. + *
+ * This is a reflective preview API to allow tools running in Java runtime + * environments with no preview feature enabled to access information + * related to preview features. + *
+ * As each Java SE release does not support preview features from any other + * release, this constant does not represent those features, and there is + * no constant representing such features this Java Runtime Environment is + * unaware of. Programmers must check the current Java SE version when + * accessing the preview VM features with this constant. + * + * @see + * JEP 12: Preview Features + * @see + * Java SE Specifications + * @since 25 + */ + @PreviewFeature(feature = PreviewFeature.Feature.LANGUAGE_MODEL, reflective = true) + CURRENT_PREVIEW(ClassFile.latestMajorVersion()); private final int major; @@ -389,6 +442,17 @@ public static ClassFileFormatVersion latest() { return RELEASE_25; } + /** + * {@return whether VM features associated with this enum constant will be + * supported by future Java SE releases} Returns {@code false} only for + * {@link #CURRENT_PREVIEW}. + * + * @since 25 + */ + public boolean isSupported() { + return this != CURRENT_PREVIEW; + } + /** * {@return the major class file version as an integer} * @jvms 4.1 The {@code ClassFile} Structure @@ -436,11 +500,15 @@ public static ClassFileFormatVersion valueOf(Runtime.Version rv) { * runtime version has a {@linkplain Runtime.Version#feature() * feature} large enough to support this class file format version * and has no other elements set. - * + *
* Class file format versions greater than or equal to {@link - * RELEASE_6} have non-{@code null} results. + * #RELEASE_6} have non-{@code null} results. {@link #isSupported() + * isSupported()} determines if runtime versions with greater + * feature support this class file format version. */ public Runtime.Version runtimeVersion() { + if (this == CURRENT_PREVIEW) + return latest().runtimeVersion(); // Starting with Java SE 6, the leading digit was the primary // way of identifying the platform version. if (this.compareTo(RELEASE_6) >= 0) { diff --git a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java index 7461815e4c502..3222b54b805b9 100644 --- a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java @@ -80,6 +80,10 @@ public enum Feature { KEY_DERIVATION, @JEP(number = 502, title = "Stable Values", status = "Preview") STABLE_VALUES, + /** + * Reflective preview APIs to access preview language and VM + * features as a whole. + */ LANGUAGE_MODEL, /** * A key for testing. 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 6bc1dab1f8ab7..3374a827e74ef 100644 --- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -25,15 +25,26 @@ package javax.lang.model; +import jdk.internal.javac.PreviewFeature; + /** * Source versions of the Java programming language. * * See the appropriate edition of * The Java Language Specification * for information about a particular source version. - * - *
Note that additional source version constants will be added to - * model future releases of the language. + *
+ * Additional source version constants will be added to model future releases + * of the language. + *
+ * A special constant, {@link #CURRENT_PREVIEW}, representing the + * preview language features of the current Java SE release, is not a source + * version, but can be viewed as a future source version. Each of the preview + * language features is described by a separate document on the site that hosts + * the corresponding edition of JLS. Unlike the features in source versions, + * the preview language features are only supported when preview features are + * enabled, and are not {@linkplain #isSupported() supported by future + * releases}. * * @since 1.6 * @see java.lang.reflect.ClassFileFormatVersion @@ -171,13 +182,13 @@ public enum SourceVersion { * Additions in this release include diamond syntax for * constructors, {@code try}-with-resources, strings in switch, * binary literals, and multi-catch. - * @since 1.7 * * @see * The Java Language Specification, Java SE 7 Edition * @see * JSR 334: Small Enhancements to the Java™ Programming Language + * @since 1.7 */ RELEASE_7, @@ -186,13 +197,13 @@ public enum SourceVersion { * 8. * * Additions in this release include lambda expressions and default methods. - * @since 1.8 * * @see * The Java Language Specification, Java SE 8 Edition * @see * JSR 335: Lambda Expressions for the Java™ Programming Language + * @since 1.8 */ RELEASE_8, @@ -203,8 +214,6 @@ public enum SourceVersion { * Additions in this release include modules and removal of a * single underscore from the set of legal identifier names. * - * @since 9 - * * @see * The Java Language Specification, Java SE 9 Edition @@ -212,6 +221,7 @@ public enum SourceVersion { * JSR 376: Java™ Platform Module System * @see * JEP 213: Milling Project Coin + * @since 9 */ RELEASE_9, @@ -222,13 +232,12 @@ public enum SourceVersion { * Additions in this release include local-variable type inference * ({@code var}). * - * @since 10 - * * @see * The Java Language Specification, Java SE 10 Edition * @see * JEP 286: Local-Variable Type Inference + * @since 10 */ RELEASE_10, @@ -239,13 +248,12 @@ public enum SourceVersion { * Additions in this release include local-variable syntax for * lambda parameters. * - * @since 11 - * * @see * The Java Language Specification, Java SE 11 Edition * @see * JEP 323: Local-Variable Syntax for Lambda Parameters + * @since 11 */ RELEASE_11, @@ -254,11 +262,10 @@ public enum SourceVersion { * 12. * No major changes from the prior release. * - * @since 12 - * * @see * The Java Language Specification, Java SE 12 Edition + * @since 12 */ RELEASE_12, @@ -267,11 +274,10 @@ public enum SourceVersion { * 13. * No major changes from the prior release. * - * @since 13 - * * @see * The Java Language Specification, Java SE 13 Edition + * @since 13 */ RELEASE_13, @@ -281,13 +287,12 @@ public enum SourceVersion { * * Additions in this release include switch expressions. * - * @since 14 - * * @see * The Java Language Specification, Java SE 14 Edition * @see * JEP 361: Switch Expressions + * @since 14 */ RELEASE_14, @@ -297,13 +302,12 @@ public enum SourceVersion { * * Additions in this release include text blocks. * - * @since 15 - * * @see * The Java Language Specification, Java SE 15 Edition * @see * JEP 378: Text Blocks + * @since 15 */ RELEASE_15, @@ -314,8 +318,6 @@ public enum SourceVersion { * Additions in this release include records and pattern matching * for {@code instanceof}. * - * @since 16 - * * @see * The Java Language Specification, Java SE 16 Edition @@ -323,6 +325,7 @@ public enum SourceVersion { * JEP 394: Pattern Matching for instanceof * @see * JEP 395: Records + * @since 16 */ RELEASE_16, @@ -333,8 +336,6 @@ public enum SourceVersion { * Additions in this release include sealed classes and * restoration of always-strict floating-point semantics. * - * @since 17 - * * @see * The Java Language Specification, Java SE 17 Edition @@ -342,6 +343,7 @@ public enum SourceVersion { * JEP 306: Restore Always-Strict Floating-Point Semantics * @see * JEP 409: Sealed Classes + * @since 17 */ RELEASE_17, @@ -351,11 +353,10 @@ public enum SourceVersion { * * No major changes from the prior release. * - * @since 18 - * * @see * The Java Language Specification, Java SE 18 Edition + * @since 18 */ RELEASE_18, @@ -365,11 +366,10 @@ public enum SourceVersion { * * No major changes from the prior release. * - * @since 19 - * * @see * The Java Language Specification, Java SE 19 Edition + * @since 19 */ RELEASE_19, @@ -379,11 +379,10 @@ public enum SourceVersion { * * No major changes from the prior release. * - * @since 20 - * * @see * The Java Language Specification, Java SE 20 Edition + * @since 20 */ RELEASE_20, @@ -394,8 +393,6 @@ public enum SourceVersion { * Additions in this release include record patterns and pattern * matching for {@code switch}. * - * @since 21 - * * @see * The Java Language Specification, Java SE 21 Edition @@ -403,6 +400,7 @@ public enum SourceVersion { * JEP 440: Record Patterns * @see * JEP 441: Pattern Matching for switch + * @since 21 */ RELEASE_21, @@ -413,13 +411,12 @@ public enum SourceVersion { * Additions in this release include unnamed variables and unnamed * patterns. * - * @since 22 - * * @see * The Java Language Specification, Java SE 22 Edition * @see * JEP 456: Unnamed Variables & Patterns + * @since 22 */ RELEASE_22, @@ -427,11 +424,10 @@ public enum SourceVersion { * The version introduced by the Java Platform, Standard Edition * 23. * - * @since 23 - * * @see * The Java Language Specification, Java SE 23 Edition + * @since 23 */ RELEASE_23, @@ -439,11 +435,10 @@ public enum SourceVersion { * The version introduced by the Java Platform, Standard Edition * 24. * - * @since 24 - * * @see * The Java Language Specification, Java SE 24 Edition + * @since 24 */ RELEASE_24, @@ -454,8 +449,6 @@ public enum SourceVersion { * Additions in this release include module import declarations * and compact source files and instance main methods. * - * @since 25 - * * @see * The Java Language Specification, Java SE 25 Edition @@ -463,12 +456,45 @@ public enum SourceVersion { * JEP 511: Module Import Declarations * @see * JEP 512: Compact Source Files and Instance Main Methods + * @since 25 */ RELEASE_25, - ; // Reduce code churn when appending new constants - // Note that when adding constants for newer releases, the - // behavior of latest() and latestSupported() must be updated too. + // Note to maintainers: Add new constants right above. + // The implementation of latest() must be updated too. + // Also update the dummy SourceVersion for processing/model/TestSourceVersion. + /** + * An enum constant representing all preview language features of the + * {@linkplain #latest() current Java SE release} in addition to those of + * the latest source version. Unlike language features associated to enum + * constants representing a source version, language features associated to + * this enum constant are not {@linkplain #isSupported() supported} by later + * Java SE releases. + * + * @apiNote + * While this is not a source version, it can be considered as the source + * version of an arbitrary future Java SE release. Programmers should test + * compiling their programs with preview features enabled to ensure the + * program is compatible with future Java SE releases. + *
+ * This is a reflective preview API to allows tools running in Java runtime + * environments with no preview feature enabled to access information + * related to preview features. + *
+ * As each Java SE release does not support preview features from any other + * release, this constant does not represent those features, and there is + * no constant representing such features this Java Runtime Environment is + * unaware of. Programmers must check the current Java SE version when + * accessing the preview language features with this constant. + * + * @see + * JEP 12: Preview Features + * @see + * Java SE Specifications + * @since 25 + */ + @PreviewFeature(feature = PreviewFeature.Feature.LANGUAGE_MODEL, reflective = true) + CURRENT_PREVIEW; /** * {@return the latest source version that can be modeled} @@ -489,7 +515,7 @@ public static SourceVersion latest() { private static SourceVersion getLatestSupported() { int intVersion = Runtime.version().feature(); return (intVersion >= 11) ? - valueOf("RELEASE_" + Math.min(25, intVersion)): + valueOf("RELEASE_" + Math.min(latest().ordinal(), intVersion)): RELEASE_10; } @@ -498,7 +524,7 @@ private static SourceVersion getLatestSupported() { * current execution environment} {@code RELEASE_9} or later must * be returned. * - * @apiNote This method is included alongside {@link latest} to + * @apiNote This method is included alongside {@link #latest} to * allow identification of situations where the language model API * is running on a platform version different from the latest * version modeled by the API. One way that sort of situation can @@ -746,18 +772,34 @@ public static SourceVersion valueOf(Runtime.Version rv) { return valueOf("RELEASE_" + rv.feature()); } + /** + * {@return whether language features associated with this enum constant + * will be supported by future Java SE releases} Returns {@code false} only + * for {@link #CURRENT_PREVIEW}. + * + * @since 25 + */ + public boolean isSupported() { + return this != CURRENT_PREVIEW; + } + /** * {@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.
+ * have non-{@code null} results. {@link #isSupported() isSupported()}
+ * determines if runtime versions with greater feature support this source
+ * version.
+ *
* @since 18
*/
public Runtime.Version runtimeVersion() {
+ if (this == CURRENT_PREVIEW)
+ return latest().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) {
diff --git a/test/jdk/java/lang/reflect/ClassFileFormatVersionTest.java b/test/jdk/java/lang/reflect/ClassFileFormatVersionTest.java
new file mode 100644
index 0000000000000..9262a4130c082
--- /dev/null
+++ b/test/jdk/java/lang/reflect/ClassFileFormatVersionTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2025, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.classfile.ClassFile;
+import java.lang.reflect.ClassFileFormatVersion;
+import java.util.Arrays;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static java.lang.reflect.ClassFileFormatVersion.CURRENT_PREVIEW;
+import static java.lang.reflect.ClassFileFormatVersion.latest;
+import static org.junit.jupiter.api.Assertions.*;
+
+/*
+ * @test
+ * @bug 8355536
+ * @summary Sanity test for ClassFileFormatVersion
+ * @run junit ClassFileFormatVersionTest
+ */
+class ClassFileFormatVersionTest {
+ @Test
+ void testLatest() {
+ var latest = ClassFileFormatVersion.latest();
+ assertNotSame(CURRENT_PREVIEW, latest);
+ assertEquals(ClassFile.latestMajorVersion(), latest.major());
+ assertTrue(latest.isSupported());
+ assertEquals(ClassFileFormatVersion.values().length - 2, latest.ordinal());
+ }
+
+ @Test
+ void testCurrentPreview() {
+ assertTrue(ClassFileFormatVersion.latest().compareTo(CURRENT_PREVIEW) < 0);
+ assertEquals(ClassFile.latestMajorVersion(), CURRENT_PREVIEW.major());
+ assertFalse(CURRENT_PREVIEW.isSupported());
+ assertEquals(ClassFileFormatVersion.values().length - 1, CURRENT_PREVIEW.ordinal());
+ assertEquals(latest().runtimeVersion(), CURRENT_PREVIEW.runtimeVersion());
+ }
+
+ static Stream
+ * Additional source version constants will be added to model future releases
+ * of the language.
+ *
+ * A special constant, {@link #CURRENT_PREVIEW}, representing the
+ * preview language features of the current Java SE release, is not a source
+ * version, but can be viewed as a future source version. Each of the preview
+ * language features is described by a separate document on the site that hosts
+ * the corresponding edition of JLS. Unlike the features in source versions,
+ * the preview language features are only supported when preview features are
+ * enabled, and are not {@linkplain #isSupported() supported by future
+ * releases}.
+ *
+ * @since 1.6
+ * @see java.lang.reflect.ClassFileFormatVersion
+ */
+public enum SourceVersion {
+ /*
+ * Summary of language evolution
+ * 1.1: nested classes
+ * 1.2: strictfp
+ * 1.3: no changes
+ * 1.4: assert
+ * 1.5: annotations, generics, autoboxing, var-args...
+ * 1.6: no changes
+ * 1.7: diamond syntax, try-with-resources, etc.
+ * 1.8: lambda expressions and default methods
+ * 9: modules, small cleanups to 1.7 and 1.8 changes
+ * 10: local-variable type inference (var)
+ * 11: local-variable syntax for lambda parameters
+ * 12: no changes (switch expressions in preview)
+ * 13: no changes (text blocks in preview; switch expressions in
+ * second preview)
+ * 14: switch expressions (pattern matching and records in
+ * preview; text blocks in second preview)
+ * 15: text blocks (sealed classes in preview; records and pattern
+ * matching in second preview)
+ * 16: records and pattern matching (sealed classes in second preview)
+ * 17: sealed classes, floating-point always strict (pattern
+ * matching for switch in preview)
+ * 18: no changes (pattern matching for switch in second preview)
+ * 19: no changes (pattern matching for switch in third preview,
+ * record patterns in preview)
+ * 20: no changes (pattern matching for switch in fourth preview,
+ * record patterns in second preview)
+ * 21: pattern matching for switch and record patterns (string
+ * templates in preview, unnamed patterns and variables in
+ * preview, unnamed classes and instance main methods in preview)
+ * 22: unnamed variables & patterns (statements before super(...)
+ * in preview, string templates in second preview, implicitly
+ * declared classes and instance main methods in second preview)
+ * 23: no changes (primitive Types in Patterns, instanceof, and
+ * switch in preview, module Import Declarations in preview,
+ * implicitly declared classes and instance main in third
+ * preview, flexible constructor bodies in second preview)
+ * 24: no changes (primitive Types in Patterns, instanceof, and
+ * switch in second preview, module Import Declarations in second
+ * preview, simple source files and instance main in fourth
+ * preview, flexible constructor bodies in third preview)
+ * 25: module import declarations, compact source files and
+ * instance main methods,
+ */
+
+ /**
+ * The original version.
+ *
+ * The language described in
+ * The Java Language Specification, First Edition.
+ */
+ RELEASE_0,
+
+ /**
+ * The version introduced by the Java Platform 1.1.
+ *
+ * The language is {@code RELEASE_0} augmented with nested classes
+ * as described in the 1.1 update to The Java Language
+ * Specification, First Edition.
+ */
+ RELEASE_1,
+
+ /**
+ * The version introduced by the Java 2 Platform, Standard Edition,
+ * v 1.2.
+ *
+ * The language described in
+ * The Java Language Specification,
+ * Second Edition, which includes the {@code
+ * strictfp} modifier.
+ */
+ RELEASE_2,
+
+ /**
+ * The version introduced by the Java 2 Platform, Standard Edition,
+ * v 1.3.
+ *
+ * No major changes from {@code RELEASE_2}.
+ */
+ RELEASE_3,
+
+ /**
+ * The version introduced by the Java 2 Platform, Standard Edition,
+ * v 1.4.
+ *
+ * Added a simple assertion facility.
+ *
+ * @see
+ * JSR 41: A Simple Assertion Facility
+ */
+ RELEASE_4,
+
+ /**
+ * The version introduced by the Java 2 Platform, Standard
+ * Edition 5.0.
+ *
+ * The language described in
+ * The Java Language Specification,
+ * Third Edition. First release to support
+ * generics, annotations, autoboxing, var-args, enhanced {@code
+ * for} loop, and hexadecimal floating-point literals.
+ *
+ * @see
+ * JSR 14: Add Generic Types To The Java™ Programming Language
+ * @see
+ * JSR 175: A Metadata Facility for the Java™ Programming Language
+ * @see
+ * JSR 201: Extending the Java™ Programming Language with Enumerations,
+ * Autoboxing, Enhanced for loops and Static Import
+ */
+ RELEASE_5,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 6.
+ *
+ * No major changes from {@code RELEASE_5}.
+ *
+ * @see
+ * The Java Language Specification, Third Edition
+ */
+ RELEASE_6,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 7.
+ *
+ * Additions in this release include diamond syntax for
+ * constructors, {@code try}-with-resources, strings in switch,
+ * binary literals, and multi-catch.
+ *
+ * @see
+ * The Java Language Specification, Java SE 7 Edition
+ * @see
+ * JSR 334: Small Enhancements to the Java™ Programming Language
+ * @since 1.7
+ */
+ RELEASE_7,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 8.
+ *
+ * Additions in this release include lambda expressions and default methods.
+ *
+ * @see
+ * The Java Language Specification, Java SE 8 Edition
+ * @see
+ * JSR 335: Lambda Expressions for the Java™ Programming Language
+ * @since 1.8
+ */
+ RELEASE_8,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 9.
+ *
+ * Additions in this release include modules and removal of a
+ * single underscore from the set of legal identifier names.
+ *
+ * @see
+ * The Java Language Specification, Java SE 9 Edition
+ * @see
+ * JSR 376: Java™ Platform Module System
+ * @see
+ * JEP 213: Milling Project Coin
+ * @since 9
+ */
+ RELEASE_9,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 10.
+ *
+ * Additions in this release include local-variable type inference
+ * ({@code var}).
+ *
+ * @see
+ * The Java Language Specification, Java SE 10 Edition
+ * @see
+ * JEP 286: Local-Variable Type Inference
+ * @since 10
+ */
+ RELEASE_10,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 11.
+ *
+ * Additions in this release include local-variable syntax for
+ * lambda parameters.
+ *
+ * @see
+ * The Java Language Specification, Java SE 11 Edition
+ * @see
+ * JEP 323: Local-Variable Syntax for Lambda Parameters
+ * @since 11
+ */
+ RELEASE_11,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 12.
+ * No major changes from the prior release.
+ *
+ * @see
+ * The Java Language Specification, Java SE 12 Edition
+ * @since 12
+ */
+ RELEASE_12,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 13.
+ * No major changes from the prior release.
+ *
+ * @see
+ * The Java Language Specification, Java SE 13 Edition
+ * @since 13
+ */
+ RELEASE_13,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 14.
+ *
+ * Additions in this release include switch expressions.
+ *
+ * @see
+ * The Java Language Specification, Java SE 14 Edition
+ * @see
+ * JEP 361: Switch Expressions
+ * @since 14
+ */
+ RELEASE_14,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 15.
+ *
+ * Additions in this release include text blocks.
+ *
+ * @see
+ * The Java Language Specification, Java SE 15 Edition
+ * @see
+ * JEP 378: Text Blocks
+ * @since 15
+ */
+ RELEASE_15,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 16.
+ *
+ * Additions in this release include records and pattern matching
+ * for {@code instanceof}.
+ *
+ * @see
+ * The Java Language Specification, Java SE 16 Edition
+ * @see
+ * JEP 394: Pattern Matching for instanceof
+ * @see
+ * JEP 395: Records
+ * @since 16
+ */
+ RELEASE_16,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 17.
+ *
+ * Additions in this release include sealed classes and
+ * restoration of always-strict floating-point semantics.
+ *
+ * @see
+ * The Java Language Specification, Java SE 17 Edition
+ * @see
+ * JEP 306: Restore Always-Strict Floating-Point Semantics
+ * @see
+ * JEP 409: Sealed Classes
+ * @since 17
+ */
+ RELEASE_17,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 18.
+ *
+ * No major changes from the prior release.
+ *
+ * @see
+ * The Java Language Specification, Java SE 18 Edition
+ * @since 18
+ */
+ RELEASE_18,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 19.
+ *
+ * No major changes from the prior release.
+ *
+ * @see
+ * The Java Language Specification, Java SE 19 Edition
+ * @since 19
+ */
+ RELEASE_19,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 20.
+ *
+ * No major changes from the prior release.
+ *
+ * @see
+ * The Java Language Specification, Java SE 20 Edition
+ * @since 20
+ */
+ RELEASE_20,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 21.
+ *
+ * Additions in this release include record patterns and pattern
+ * matching for {@code switch}.
+ *
+ * @see
+ * The Java Language Specification, Java SE 21 Edition
+ * @see
+ * JEP 440: Record Patterns
+ * @see
+ * JEP 441: Pattern Matching for switch
+ * @since 21
+ */
+ RELEASE_21,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 22.
+ *
+ * Additions in this release include unnamed variables and unnamed
+ * patterns.
+ *
+ * @see
+ * The Java Language Specification, Java SE 22 Edition
+ * @see
+ * JEP 456: Unnamed Variables & Patterns
+
+ * @since 22
+ */
+ RELEASE_22,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 23.
+ *
+ * @see
+ * The Java Language Specification, Java SE 23 Edition
+ * @since 23
+ */
+ RELEASE_23,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 24.
+ *
+ * @see
+ * The Java Language Specification, Java SE 24 Edition
+ * @since 24
+ */
+ RELEASE_24,
+
+ /**
+ * The version introduced by the Java Platform, Standard Edition
+ * 25.
+ *
+ * Additions in this release include module import declarations
+ * and compact source files and instance main methods.
+ *
+ * @see
+ * The Java Language Specification, Java SE 25 Edition
+ * @see
+ * JEP 511: Module Import Declarations
+ * @see
+ * JEP 512: Compact Source Files and Instance Main Methods
+ * @since 25
+ */
+ RELEASE_25,
+ RELEASE_26,
+
+ // Note to maintainers: Add new constants right above.
+ // The implementation of latest() must be updated too.
+ // Also update the dummy SourceVersion for processing/model/TestSourceVersion.
+ /**
+ * An enum constant representing all preview language features of the
+ * {@linkplain #latest() current Java SE release} in addition to those of
+ * the latest source version. Unlike language features associated to enum
+ * constants representing a source version, language features associated to
+ * this enum constant are not {@linkplain #isSupported() supported} by later
+ * Java SE releases.
+ *
+ * @apiNote
+ * While this is not a source version, it can be considered as the source
+ * version of an arbitrary future Java SE release. Programmers should test
+ * compiling their programs with preview features enabled to ensure the
+ * program is compatible with future Java SE releases.
+ *
+ * This is a reflective preview API to allows tools running in Java runtime
+ * environments with no preview feature enabled to access information
+ * related to preview features.
+ *
+ * As each Java SE release does not support preview features from any other
+ * release, this constant does not represent those features, and there is
+ * no constant representing such features this Java Runtime Environment is
+ * unaware of. Programmers must check the current Java SE version when
+ * accessing the preview language features with this constant.
+ *
+ * @see
+ * JEP 12: Preview Features
+ * @see
+ * Java SE Specifications
+ * @since 25
+ */
+ @PreviewFeature(feature = PreviewFeature.Feature.LANGUAGE_MODEL, reflective = true)
+ CURRENT_PREVIEW;
+
+ /**
+ * {@return the latest source version that can be modeled}
+ */
+ public static SourceVersion latest() {
+ return RELEASE_26;
+ }
+
+ private static final SourceVersion latestSupported = getLatestSupported();
+
+ /*
+ * The integer version to enum constant mapping implemented by
+ * this method assumes the JEP 322: "Time-Based Release
+ * Versioning" scheme is in effect. This scheme began in JDK
+ * 10. If the JDK versioning scheme is revised, this method may
+ * need to be updated accordingly.
+ */
+ private static SourceVersion getLatestSupported() {
+ int intVersion = Runtime.version().feature();
+ return (intVersion >= 11) ?
+ valueOf("RELEASE_" + Math.min(latest().ordinal(), intVersion)):
+ RELEASE_10;
+ }
+
+ /**
+ * {@return the latest source version fully supported by the
+ * current execution environment} {@code RELEASE_9} or later must
+ * be returned.
+ *
+ * @apiNote This method is included alongside {@link #latest} to
+ * allow identification of situations where the language model API
+ * is running on a platform version different from the latest
+ * version modeled by the API. One way that sort of situation can
+ * occur is if an IDE or similar tool is using the API to model
+ * source version N while running on platform version
+ * (N - 1). Running in this configuration is
+ * supported by the API. Running an API on platform versions
+ * earlier than (N - 1) or later than N
+ * may or may not work as an implementation detail. If an
+ * annotation processor was generating code to run under the
+ * current execution environment, the processor should only use
+ * platform features up to the {@code latestSupported} release,
+ * which may be earlier than the {@code latest} release.
+ */
+ public static SourceVersion latestSupported() {
+ return latestSupported;
+ }
+
+ /**
+ * Returns whether or not {@code name} is a syntactically valid
+ * identifier (simple name) or keyword in the latest source
+ * version. The method returns {@code true} if the name consists
+ * of an initial character for which {@link
+ * Character#isJavaIdentifierStart(int)} returns {@code true},
+ * followed only by characters for which {@link
+ * Character#isJavaIdentifierPart(int)} returns {@code true}.
+ * This pattern matches regular identifiers, keywords, contextual
+ * keywords, boolean literals, and the null literal.
+ *
+ * The method returns {@code false} for all other strings.
+ *
+ * @param name the string to check
+ * @return {@code true} if this string is a
+ * syntactically valid identifier or keyword, {@code false}
+ * otherwise.
+ *
+ * @jls 3.8 Identifiers
+ */
+ public static boolean isIdentifier(CharSequence name) {
+ String id = name.toString();
+
+ if (id.length() == 0) {
+ return false;
+ }
+ int cp = id.codePointAt(0);
+ if (!Character.isJavaIdentifierStart(cp)) {
+ return false;
+ }
+ for (int i = Character.charCount(cp);
+ i < id.length();
+ i += Character.charCount(cp)) {
+ cp = id.codePointAt(i);
+ if (!Character.isJavaIdentifierPart(cp)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns whether or not {@code name} is a syntactically valid
+ * qualified name in the latest source version.
+ *
+ * Syntactically, a qualified name is a sequence of identifiers
+ * separated by period characters ("{@code .}"). This method
+ * splits the input string into period-separated segments and
+ * applies checks to each segment in turn.
+ *
+ * Unlike {@link #isIdentifier isIdentifier}, this method returns
+ * {@code false} for keywords, boolean literals, and the null
+ * literal in any segment.
+ *
+ * This method returns {@code true} for contextual
+ * keywords.
+ *
+ * @param name the string to check
+ * @return {@code true} if this string is a
+ * syntactically valid name, {@code false} otherwise.
+ * @jls 3.9 Keywords
+ * @jls 6.2 Names and Identifiers
+ */
+ public static boolean isName(CharSequence name) {
+ return isName(name, latest());
+ }
+
+ /**
+ * Returns whether or not {@code name} is a syntactically valid
+ * qualified name in the given source version.
+ *
+ * Syntactically, a qualified name is a sequence of identifiers
+ * separated by period characters ("{@code .}"). This method
+ * splits the input string into period-separated segments and
+ * applies checks to each segment in turn.
+ *
+ * Unlike {@link #isIdentifier isIdentifier}, this method returns
+ * {@code false} for keywords, boolean literals, and the null
+ * literal in any segment.
+ *
+ * This method returns {@code true} for contextual
+ * keywords.
+ *
+ * @param name the string to check
+ * @param version the version to use
+ * @return {@code true} if this string is a
+ * syntactically valid name, {@code false} otherwise.
+ * @jls 3.9 Keywords
+ * @jls 6.2 Names and Identifiers
+ * @since 9
+ */
+ public static boolean isName(CharSequence name, SourceVersion version) {
+ String id = name.toString();
+
+ for(String s : id.split("\\.", -1)) {
+ if (!isIdentifier(s) || isKeyword(s, version))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns whether or not {@code s} is a keyword, a boolean literal,
+ * or the null literal in the latest source version.
+ * This method returns {@code false} for contextual
+ * keywords.
+ *
+ * @param s the string to check
+ * @return {@code true} if {@code s} is a keyword, a boolean
+ * literal, or the null literal, {@code false} otherwise.
+ * @jls 3.9 Keywords
+ * @jls 3.10.3 Boolean Literals
+ * @jls 3.10.8 The Null Literal
+ */
+ public static boolean isKeyword(CharSequence s) {
+ return isKeyword(s, latest());
+ }
+
+ /**
+ * Returns whether or not {@code s} is a keyword, a boolean literal,
+ * or the null literal in the given source version.
+ * This method returns {@code false} for contextual
+ * keywords.
+ *
+ * @param s the string to check
+ * @param version the version to use
+ * @return {@code true} if {@code s} is a keyword, a boolean
+ * literal, or the null literal, {@code false} otherwise.
+ * @jls 3.9 Keywords
+ * @jls 3.10.3 Boolean Literals
+ * @jls 3.10.8 The Null Literal
+ * @since 9
+ */
+ public static boolean isKeyword(CharSequence s, SourceVersion version) {
+ String id = s.toString();
+ switch(id) {
+ // A trip through history
+ case "strictfp":
+ return version.compareTo(RELEASE_2) >= 0;
+
+ case "assert":
+ return version.compareTo(RELEASE_4) >= 0;
+
+ case "enum":
+ return version.compareTo(RELEASE_5) >= 0;
+
+ case "_":
+ return version.compareTo(RELEASE_9) >= 0;
+
+ // case "non-sealed": can be added once it is a keyword only
+ // dependent on release and not also preview features being
+ // enabled.
+
+ // Keywords common across versions
+
+ // Modifiers
+ case "public": case "protected": case "private":
+ case "abstract": case "static": case "final":
+ case "transient": case "volatile": case "synchronized":
+ case "native":
+
+ // Declarations
+ case "class": case "interface": case "extends":
+ case "package": case "throws": case "implements":
+
+ // Primitive types and void
+ case "boolean": case "byte": case "char":
+ case "short": case "int": case "long":
+ case "float": case "double":
+ case "void":
+
+ // Control flow
+ case "if": case "else":
+ case "try": case "catch": case "finally":
+ case "do": case "while":
+ case "for": case "continue":
+ case "switch": case "case": case "default":
+ case "break": case "throw": case "return":
+
+ // Other keywords
+ case "this": case "new": case "super":
+ case "import": case "instanceof":
+
+ // Forbidden!
+ case "goto": case "const":
+
+ // literals
+ case "null": case "true": case "false":
+ return true;
+
+ default:
+ 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:
+ *
+ * {@snippet lang="java" :
+ * 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 whether language features associated with this enum constant
+ * will be supported by future Java SE releases} Returns {@code false} only
+ * for {@link #CURRENT_PREVIEW}.
+ *
+ * @since 25
+ */
+ public boolean isSupported() {
+ return this != CURRENT_PREVIEW;
+ }
+
+ /**
+ * {@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. {@link #isSupported() isSupported()}
+ * determines if runtime versions with greater feature support this source
+ * version.
+ *
+ * @since 18
+ */
+ public Runtime.Version runtimeVersion() {
+ if (this == CURRENT_PREVIEW)
+ return latest().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;
+ }
+ }
+}