Summary
-------
Add an `enum` class to model the class file format version and use those constants to return version-specific information about access flags.
Problem
-------
The applicability of access flags and other JVM structures are class file format version specific. Adding an `enum` class to model the versioning allows more precise information to be returned.
Solution
--------
Add `java/lang/reflect/ClassFileFormatVersion` as an `enum` class and add the method `AccessFlags.locations(ClassFileFormatVersion cffv)`.
Updating `ClassFileFormatVersion` would be part of the start-of-release set of changes.
Specification
-------------
diff --git a/src/java.base/share/classes/java/lang/reflect/AccessFlag.java b/src/java.base/share/classes/java/lang/reflect/AccessFlag.java
index 785a9d798fd..5debc6fdaef 100644
--- a/src/java.base/share/classes/java/lang/reflect/AccessFlag.java
+++ b/src/java.base/share/classes/java/lang/reflect/AccessFlag.java
@@ -70,7 +70,7 @@ import static java.util.Map.entry;
* added at the end of the existing list.
*
* @apiNote
- * The JVM class file format has a new version defined for each new
+ * The JVM class file format has a {@linkplain ClassFileFormatVersion new version} defined for each new
* {@linkplain Runtime.Version#feature() feature release}. A new class
* file version may define new access flags or retire old ones. {@code
* AccessFlag} is intended to model the set of access flags across
...
@@ -306,12 +455,23 @@ public enum AccessFlag {
}
/**
- * {@return kinds of constructs the flag can be applied to}
+ * {@return kinds of constructs the flag can be applied to in the
+ * latest class file format version}
*/
public Set<Location> locations() {
return locations;
}
+ /**
+ * {@return kinds of constructs the flag can be applied to in the
+ * given class file format version}
+ * @param cffv the class file format version to use
+ * @throws NullPointerException if the parameter is {@code null}
+ */
+ public Set<Location> locations(ClassFileFormatVersion cffv) {
+ return locations; // Default to supported unchanging locations
+ }
+
/**
* {@return an unmodifiable set of access flags for the given mask value
* appropriate for the location in question}
diff --git a/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java b/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java
new file mode 100644
index 00000000000..0faf46b2180
--- /dev/null
+++ b/src/java.base/share/classes/java/lang/reflect/ClassFileFormatVersion.java
@@ -0,0 +1,350 @@
+package java.lang.reflect;
+
+/**
+ * Class file format versions of the Java virtual machine.
+ *
+ * See the appropriate edition of <cite>The Java Virtual Machine
+ * Specification</cite> for information about a particular class file
+ * format version.
+ *
+ * <p>Note that additional class file format version constants will be
+ * added to model future releases of the Java Virtual Machine
+ * Specification.
+ *
+ * @since 20
+ * @see System#getProperties System property {@code java.class.version}
+ * @see java.compiler/javax.lang.model.SourceVersion
+ */
+@SuppressWarnings("doclint:reference") // cross-module links
+public enum ClassFileFormatVersion {
+
+ /**
+ * The original version.
+ *
+ * The format described in <cite>The Java Virtual Specification,
+ * First Edition</cite>.
+ */
+ RELEASE_0(45),
+
+ /**
+ * The version recognized by the Java Platform 1.1.
+ *
+ * @apiNote
+ * While {@code RELEASE_0} and {@code RELEASE_1} have the same
+ * {@linkplain #major() major version}, several additional
+ * attributes were defined for {@code RELEASE_1} (JVMS {@jvms
+ * 4.7}).
+ *
+ */
+ RELEASE_1(45),
+
+ /**
+ * The version recognized by the Java 2 Platform, Standard Edition,
+ * v 1.2.
+ *
+ * The format described in <cite>The Java Virtual Machine
+ * Specification, Second Edition</cite>, which includes the {@link
+ * AccessFlag#STRICT ACC_STRICT} access flag.
+ */
+ RELEASE_2(46),
+
+ /**
+ * The version recognized by the Java 2 Platform, Standard Edition,
+ * v 1.3.
+ */
+ RELEASE_3(47),
+
+ /**
+ * The version recognized by the Java 2 Platform, Standard Edition,
+ * v 1.4.
+ */
+ RELEASE_4(48),
+
+ /**
+ * The version recognized by the Java 2 Platform, Standard
+ * Edition 5.0.
+ *
+ * @see <a
+ * href="https://jcp.org/aboutJava/communityprocess/maintenance/jsr924/index.html">
+ * <cite>The Java Virtual Machine Specification, Second Edition updated for Java SE 5.0</cite></a>
+ * @see <a href="https://jcp.org/en/jsr/detail?id=14">
+ * JSR 14: Add Generic Types To The Java™ Programming Language</a>
+ * @see <a href="https://jcp.org/en/jsr/detail?id=175">
+ * JSR 175: A Metadata Facility for the Java™ Programming Language</a>
+ */
+ RELEASE_5(49),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 6.
+ *
+ * @see <a
+ * href="https://jcp.org/aboutJava/communityprocess/maintenance/jsr924/index2.html">
+ * <cite>The Java Virtual Machine Specification, Java SE, Second Edition updated for Java SE 6</cite></a>
+ */
+ RELEASE_6(50),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 7.
+ *
+ * @see <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se7/html/index.html">
+ * <cite>The Java Virtual Machine Specification, Java SE 7 Edition</cite></a>
+ */
+ RELEASE_7(51),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 8.
+ *
+ * @see <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se8/html/index.html">
+ * <cite>The Java Virtual Machine Specification, Java SE 8 Edition</cite></a>
+ * @see <a href="https://jcp.org/en/jsr/detail?id=335">
+ * JSR 335: Lambda Expressions for the Java™ Programming Language</a>
+ */
+ RELEASE_8(52),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 9.
+ *
+ * @see <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se9/html/index.html">
+ * <cite>The Java Virtual Machine Specification, Java SE 9 Edition</cite></a>
+ * @see <a href="https://jcp.org/en/jsr/detail?id=376">
+ * JSR 376: Java™ Platform Module System</a>
+ */
+ RELEASE_9(53),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 10.
+ *
+ * @see <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se10/html/index.html">
+ * <cite>The Java Virtual Machine Specification, Java SE 10 Edition</cite></a>
+ */
+ RELEASE_10(54),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 11.
+ *
+ * @see <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se11/html/index.html">
+ * <cite>The Java Virtual Machine Specification, Java SE 11 Edition</cite></a>
+ * @see <a href="https://openjdk.java.net/jeps/181">
+ * JEP 181: Nest-Based Access Control</a>
+ */
+ RELEASE_11(55),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 12.
+ *
+ * @see <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se12/html/index.html">
+ * <cite>The Java Virtual Machine Specification, Java SE 12 Edition</cite></a>
+ */
+ RELEASE_12(56),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 13.
+ *
+ * @see <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se13/html/index.html">
+ * <cite>The Java Virtual Machine Specification, Java SE 13 Edition</cite></a>
+ */
+ RELEASE_13(57),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 14.
+ *
+ * @see <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se14/html/index.html">
+ * <cite>The Java Virtual Machine Specification, Java SE 14 Edition</cite></a>
+ */
+ RELEASE_14(58),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 15.
+ *
+ * @see <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se15/html/index.html">
+ * <cite>The Java Virtual Machine Specification, Java SE 15 Edition</cite></a>
+ * @see <a href="https://openjdk.java.net/jeps/371">
+ * JEP 371: Hidden Classes</a>
+ */
+ RELEASE_15(59),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 16.
+ *
+ * @see <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se16/html/index.html">
+ * <cite>The Java Virtual Machine Specification, Java SE 16 Edition</cite></a>
+ */
+ RELEASE_16(60),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 17.
+ *
+ * Additions in this release include sealed classes and
+ * restoration of always-strict floating-point semantics.
+ *
+ * @see <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se17/html/index.html">
+ * <cite>The Java Virtual Machine Specification, Java SE 17 Edition</cite></a>
+ * @see <a href="https://openjdk.java.net/jeps/306">
+ * JEP 306: Restore Always-Strict Floating-Point Semantics</a>
+ * @see <a href="https://openjdk.java.net/jeps/409">
+ * JEP 409: Sealed Classes</a>
+ */
+ RELEASE_17(61),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 18.
+ *
+ * @see <a
+ * href="https://docs.oracle.com/javase/specs/jvms/se18/html/index.html">
+ * <cite>The Java Virtual Machine Specification, Java SE 18 Edition</cite></a>
+ */
+ RELEASE_18(62),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 19.
+ */
+ RELEASE_19(63),
+
+ /**
+ * The version recognized by the Java Platform, Standard Edition
+ * 20.
+ */
+ RELEASE_20(64);
+
+ private int major;
+
+ private ClassFileFormatVersion(int major) {
+ this.major = major;
+ }
+
+ /**
+ * {@return the latest class file format version}
+ */
+ public static ClassFileFormatVersion latest() {
+ return RELEASE_20;
+ }
+
+ /**
+ * {@return the major class file version as an integer}
+ * @jvms 4.1 The {@code ClassFile} Structure
+ */
+ public int major() {
+ return major;
+ }
+
+ /**
+ * {@return the latest class file format 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 class file format
+ * version}, an {@code IllegalArgumentException} is thrown.
+ *
+ * <p>Because the class file format versions of the Java platform
+ * have so far followed a linear progression, only the feature
+ * component of a runtime version is queried to determine the
+ * mapping to a class file format 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 class file format version,
+ * {@code RELEASE_17}, is:
+ *
+ * {@snippet lang="java" :
+ * ClassFileFormatVersion.valueOf(Runtime.Version.parse("17"))}
+ *
+ * @param rv runtime version to map to a class file format version
+ * @throws IllegalArgumentException if the feature of version
+ * argument is greater than the feature of the platform version.
+ */
+ public static ClassFileFormatVersion 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 class
+ * file format version; otherwise {@code null}} The returned
+ * 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.
+ */
+ public Runtime.Version runtimeVersion() {
+ // Starting with Java SE 6, the leading digit was the primary
+ // way of identifying the platform version.
+ if (this.compareTo(RELEASE_6) >= 0) {
+ return Runtime.Version.parse(Integer.toString(ordinal()));
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * {@return the latest class file format version whose major class
+ * file version matches the argument}
+ * @param major the major class file version as an integer
+ * @throws IllegalArgumentException if the argument is outside of
+ * the range of major class file versions
+ */
+ public static ClassFileFormatVersion fromMajor(int major) {
+ if (major < 45 // RELEASE_0.major()
+ || major > latest().major()) {
+ throw new IllegalArgumentException("Out of range major class file vesion "
+ + major);
+ }
+ // RELEASE_0 and RELEASE_1 both have a major version of 45;
+ // return RELEASE_1 for an argument of 45.
+ return values()[major-44];
+ }
+}