8289106: Add model of class file versions to core reflection
Reviewed-by: rriggs
This commit is contained in:
parent
c3d3662e52
commit
e44e3f0c19
@ -28,6 +28,7 @@ package java.lang.reflect;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import static java.util.Map.entry;
|
import static java.util.Map.entry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,7 +71,7 @@ import static java.util.Map.entry;
|
|||||||
* added at the end of the existing list.
|
* added at the end of the existing list.
|
||||||
*
|
*
|
||||||
* @apiNote
|
* @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
|
* {@linkplain Runtime.Version#feature() feature release}. A new class
|
||||||
* file version may define new access flags or retire old ones. {@code
|
* file version may define new access flags or retire old ones. {@code
|
||||||
* AccessFlag} is intended to model the set of access flags across
|
* AccessFlag} is intended to model the set of access flags across
|
||||||
@ -97,29 +98,44 @@ public enum AccessFlag {
|
|||||||
* <code>{@value "0x%04x" Modifier#PUBLIC}</code>.
|
* <code>{@value "0x%04x" Modifier#PUBLIC}</code>.
|
||||||
*/
|
*/
|
||||||
PUBLIC(Modifier.PUBLIC, true,
|
PUBLIC(Modifier.PUBLIC, true,
|
||||||
Set.of(Location.CLASS, Location.FIELD, Location.METHOD,
|
Location.SET_PUBLIC_1,
|
||||||
Location.INNER_CLASS)),
|
cffv -> {
|
||||||
|
return (cffv == ClassFileFormatVersion.RELEASE_0) ?
|
||||||
|
Location.SET_CLASS_FIELD_METHOD:
|
||||||
|
Location.SET_PUBLIC_1;
|
||||||
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_PRIVATE}, corresponding to the
|
* The access flag {@code ACC_PRIVATE}, corresponding to the
|
||||||
* source modifier {@link Modifier#PRIVATE private} with a mask
|
* source modifier {@link Modifier#PRIVATE private} with a mask
|
||||||
* value of <code>{@value "0x%04x" Modifier#PRIVATE}</code>.
|
* value of <code>{@value "0x%04x" Modifier#PRIVATE}</code>.
|
||||||
*/
|
*/
|
||||||
PRIVATE(Modifier.PRIVATE, true, Location.SET_FIELD_METHOD_INNER_CLASS),
|
PRIVATE(Modifier.PRIVATE, true, Location.SET_FIELD_METHOD_INNER_CLASS,
|
||||||
|
cffv -> {
|
||||||
|
return (cffv == ClassFileFormatVersion.RELEASE_0) ?
|
||||||
|
Location.SET_FIELD_METHOD:
|
||||||
|
Location.SET_FIELD_METHOD_INNER_CLASS;
|
||||||
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_PROTECTED}, corresponding to the
|
* The access flag {@code ACC_PROTECTED}, corresponding to the
|
||||||
* source modifier {@link Modifier#PROTECTED protected} with a mask
|
* source modifier {@link Modifier#PROTECTED protected} with a mask
|
||||||
* value of <code>{@value "0x%04x" Modifier#PROTECTED}</code>.
|
* value of <code>{@value "0x%04x" Modifier#PROTECTED}</code>.
|
||||||
*/
|
*/
|
||||||
PROTECTED(Modifier.PROTECTED, true, Location.SET_FIELD_METHOD_INNER_CLASS),
|
PROTECTED(Modifier.PROTECTED, true, Location.SET_FIELD_METHOD_INNER_CLASS,
|
||||||
|
cffv -> {return (cffv == ClassFileFormatVersion.RELEASE_0) ?
|
||||||
|
Location.SET_FIELD_METHOD:
|
||||||
|
Location.SET_FIELD_METHOD_INNER_CLASS;}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_STATIC}, corresponding to the source
|
* The access flag {@code ACC_STATIC}, corresponding to the source
|
||||||
* modifier {@link Modifier#STATIC static} with a mask value of
|
* modifier {@link Modifier#STATIC static} with a mask value of
|
||||||
* <code>{@value "0x%04x" Modifier#STATIC}</code>.
|
* <code>{@value "0x%04x" Modifier#STATIC}</code>.
|
||||||
*/
|
*/
|
||||||
STATIC(Modifier.STATIC, true, Location.SET_FIELD_METHOD_INNER_CLASS),
|
STATIC(Modifier.STATIC, true, Location.SET_FIELD_METHOD_INNER_CLASS,
|
||||||
|
cffv -> {return (cffv == ClassFileFormatVersion.RELEASE_0) ?
|
||||||
|
Location.SET_FIELD_METHOD:
|
||||||
|
Location.SET_FIELD_METHOD_INNER_CLASS;}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_FINAL}, corresponding to the source
|
* The access flag {@code ACC_FINAL}, corresponding to the source
|
||||||
@ -127,8 +143,16 @@ public enum AccessFlag {
|
|||||||
* value of <code>{@value "0x%04x" Modifier#FINAL}</code>.
|
* value of <code>{@value "0x%04x" Modifier#FINAL}</code>.
|
||||||
*/
|
*/
|
||||||
FINAL(Modifier.FINAL, true,
|
FINAL(Modifier.FINAL, true,
|
||||||
Set.of(Location.CLASS, Location.FIELD, Location.METHOD,
|
Location.SET_FINAL_8,
|
||||||
Location.INNER_CLASS, Location.METHOD_PARAMETER)),
|
cffv -> {
|
||||||
|
if (cffv.compareTo(ClassFileFormatVersion.RELEASE_8) >= 0) {
|
||||||
|
return Location.SET_FINAL_8;
|
||||||
|
} else {
|
||||||
|
return (cffv == ClassFileFormatVersion.RELEASE_0) ?
|
||||||
|
Location.SET_CLASS_FIELD_METHOD :
|
||||||
|
Location.SET_CLASS_FIELD_METHOD_INNER_CLASS;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_SUPER} with a mask value of {@code
|
* The access flag {@code ACC_SUPER} with a mask value of {@code
|
||||||
@ -138,77 +162,96 @@ public enum AccessFlag {
|
|||||||
* In Java SE 8 and above, the JVM treats the {@code ACC_SUPER}
|
* In Java SE 8 and above, the JVM treats the {@code ACC_SUPER}
|
||||||
* flag as set in every class file (JVMS {@jvms 4.1}).
|
* flag as set in every class file (JVMS {@jvms 4.1}).
|
||||||
*/
|
*/
|
||||||
SUPER(0x0000_0020, false, Location.SET_CLASS),
|
SUPER(0x0000_0020, false, Location.SET_CLASS, null),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The module flag {@code ACC_OPEN} with a mask value of {@code
|
* The module flag {@code ACC_OPEN} with a mask value of {@code
|
||||||
* 0x0020}.
|
* 0x0020}.
|
||||||
* @see java.lang.module.ModuleDescriptor#isOpen
|
* @see java.lang.module.ModuleDescriptor#isOpen
|
||||||
*/
|
*/
|
||||||
OPEN(0x0000_0020, false, Set.of(Location.MODULE)),
|
OPEN(0x0000_0020, false, Location.SET_MODULE,
|
||||||
|
cffv -> { return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
|
||||||
|
Location.SET_MODULE:
|
||||||
|
Location.EMPTY_SET;}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The module requires flag {@code ACC_TRANSITIVE} with a mask
|
* The module requires flag {@code ACC_TRANSITIVE} with a mask
|
||||||
* value of {@code 0x0020}.
|
* value of {@code 0x0020}.
|
||||||
* @see java.lang.module.ModuleDescriptor.Requires.Modifier#TRANSITIVE
|
* @see java.lang.module.ModuleDescriptor.Requires.Modifier#TRANSITIVE
|
||||||
*/
|
*/
|
||||||
TRANSITIVE(0x0000_0020, false, Location.SET_MODULE_REQUIRES),
|
TRANSITIVE(0x0000_0020, false, Location.SET_MODULE_REQUIRES,
|
||||||
|
cffv -> {return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
|
||||||
|
Location.SET_MODULE_REQUIRES:
|
||||||
|
Location.EMPTY_SET;}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_SYNCHRONIZED}, corresponding to the
|
* The access flag {@code ACC_SYNCHRONIZED}, corresponding to the
|
||||||
* source modifier {@link Modifier#SYNCHRONIZED synchronized} with
|
* source modifier {@link Modifier#SYNCHRONIZED synchronized} with
|
||||||
* a mask value of <code>{@value "0x%04x" Modifier#SYNCHRONIZED}</code>.
|
* a mask value of <code>{@value "0x%04x" Modifier#SYNCHRONIZED}</code>.
|
||||||
*/
|
*/
|
||||||
SYNCHRONIZED(Modifier.SYNCHRONIZED, true, Location.SET_METHOD),
|
SYNCHRONIZED(Modifier.SYNCHRONIZED, true, Location.SET_METHOD, null),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The module requires flag {@code ACC_STATIC_PHASE} with a mask
|
* The module requires flag {@code ACC_STATIC_PHASE} with a mask
|
||||||
* value of {@code 0x0040}.
|
* value of {@code 0x0040}.
|
||||||
* @see java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC
|
* @see java.lang.module.ModuleDescriptor.Requires.Modifier#STATIC
|
||||||
*/
|
*/
|
||||||
STATIC_PHASE(0x0000_0040, false, Location.SET_MODULE_REQUIRES),
|
STATIC_PHASE(0x0000_0040, false, Location.SET_MODULE_REQUIRES,
|
||||||
|
cffv -> {return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
|
||||||
|
Location.SET_MODULE_REQUIRES:
|
||||||
|
Location.EMPTY_SET;}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_VOLATILE}, corresponding to the
|
* The access flag {@code ACC_VOLATILE}, corresponding to the
|
||||||
* source modifier {@link Modifier#VOLATILE volatile} with a mask
|
* source modifier {@link Modifier#VOLATILE volatile} with a mask
|
||||||
* value of <code>{@value "0x%04x" Modifier#VOLATILE}</code>.
|
* value of <code>{@value "0x%04x" Modifier#VOLATILE}</code>.
|
||||||
*/
|
*/
|
||||||
VOLATILE(Modifier.VOLATILE, true, Location.SET_FIELD),
|
VOLATILE(Modifier.VOLATILE, true, Location.SET_FIELD, null),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_BRIDGE} with a mask value of
|
* The access flag {@code ACC_BRIDGE} with a mask value of
|
||||||
* <code>{@value "0x%04x" Modifier#BRIDGE}</code>
|
* <code>{@value "0x%04x" Modifier#BRIDGE}</code>
|
||||||
* @see Method#isBridge()
|
* @see Method#isBridge()
|
||||||
*/
|
*/
|
||||||
BRIDGE(Modifier.BRIDGE, false, Location.SET_METHOD),
|
BRIDGE(Modifier.BRIDGE, false, Location.SET_METHOD,
|
||||||
|
cffv -> {return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
|
||||||
|
Location.SET_METHOD:
|
||||||
|
Location.EMPTY_SET;}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_TRANSIENT}, corresponding to the
|
* The access flag {@code ACC_TRANSIENT}, corresponding to the
|
||||||
* source modifier {@link Modifier#TRANSIENT transient} with a
|
* source modifier {@link Modifier#TRANSIENT transient} with a
|
||||||
* mask value of <code>{@value "0x%04x" Modifier#TRANSIENT}</code>.
|
* mask value of <code>{@value "0x%04x" Modifier#TRANSIENT}</code>.
|
||||||
*/
|
*/
|
||||||
TRANSIENT(Modifier.TRANSIENT, true, Location.SET_FIELD),
|
TRANSIENT(Modifier.TRANSIENT, true, Location.SET_FIELD, null),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_VARARGS} with a mask value of
|
* The access flag {@code ACC_VARARGS} with a mask value of
|
||||||
<code>{@value "0x%04x" Modifier#VARARGS}</code>.
|
<code>{@value "0x%04x" Modifier#VARARGS}</code>.
|
||||||
* @see Executable#isVarArgs()
|
* @see Executable#isVarArgs()
|
||||||
*/
|
*/
|
||||||
VARARGS(Modifier.VARARGS, false, Location.SET_METHOD),
|
VARARGS(Modifier.VARARGS, false, Location.SET_METHOD,
|
||||||
|
cffv -> {return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
|
||||||
|
Location.SET_METHOD:
|
||||||
|
Location.EMPTY_SET;}),
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_NATIVE}, corresponding to the source
|
* The access flag {@code ACC_NATIVE}, corresponding to the source
|
||||||
* modifier {@link Modifier#NATIVE native} with a mask value of
|
* modifier {@link Modifier#NATIVE native} with a mask value of
|
||||||
* <code>{@value "0x%04x" Modifier#NATIVE}</code>.
|
* <code>{@value "0x%04x" Modifier#NATIVE}</code>.
|
||||||
*/
|
*/
|
||||||
NATIVE(Modifier.NATIVE, true, Location.SET_METHOD),
|
NATIVE(Modifier.NATIVE, true, Location.SET_METHOD, null),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_INTERFACE} with a mask value of
|
* The access flag {@code ACC_INTERFACE} with a mask value of
|
||||||
* {@code 0x0200}.
|
* {@code 0x0200}.
|
||||||
* @see Class#isInterface()
|
* @see Class#isInterface()
|
||||||
*/
|
*/
|
||||||
INTERFACE(Modifier.INTERFACE, false, Location.SET_CLASS_INNER_CLASS),
|
INTERFACE(Modifier.INTERFACE, false, Location.SET_CLASS_INNER_CLASS,
|
||||||
|
cffv -> { return (cffv.compareTo(ClassFileFormatVersion.RELEASE_0) == 0 ) ?
|
||||||
|
Location.SET_CLASS:
|
||||||
|
Location.SET_CLASS_INNER_CLASS;}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_ABSTRACT}, corresponding to the
|
* The access flag {@code ACC_ABSTRACT}, corresponding to the
|
||||||
@ -216,7 +259,10 @@ public enum AccessFlag {
|
|||||||
* value of <code>{@value "0x%04x" Modifier#ABSTRACT}</code>.
|
* value of <code>{@value "0x%04x" Modifier#ABSTRACT}</code>.
|
||||||
*/
|
*/
|
||||||
ABSTRACT(Modifier.ABSTRACT, true,
|
ABSTRACT(Modifier.ABSTRACT, true,
|
||||||
Set.of(Location.CLASS, Location.METHOD, Location.INNER_CLASS)),
|
Location.SET_CLASS_METHOD_INNER_CLASS,
|
||||||
|
cffv -> { return (cffv.compareTo(ClassFileFormatVersion.RELEASE_0) == 0 ) ?
|
||||||
|
Location.SET_CLASS_METHOD:
|
||||||
|
Location.SET_CLASS_METHOD_INNER_CLASS;}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_STRICT}, corresponding to the source
|
* The access flag {@code ACC_STRICT}, corresponding to the source
|
||||||
@ -228,7 +274,12 @@ public enum AccessFlag {
|
|||||||
* major versions 46 through 60, inclusive (JVMS {@jvms 4.6}),
|
* major versions 46 through 60, inclusive (JVMS {@jvms 4.6}),
|
||||||
* corresponding to Java SE 1.2 through 16.
|
* corresponding to Java SE 1.2 through 16.
|
||||||
*/
|
*/
|
||||||
STRICT(Modifier.STRICT, true, Location.SET_METHOD),
|
STRICT(Modifier.STRICT, true, Location.SET_METHOD,
|
||||||
|
cffv -> {return (cffv.compareTo(ClassFileFormatVersion.RELEASE_2) >= 0 &&
|
||||||
|
cffv.compareTo(ClassFileFormatVersion.RELEASE_16) <= 0) ?
|
||||||
|
Location.SET_METHOD:
|
||||||
|
Location.EMPTY_SET;}),
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_SYNTHETIC} with a mask value of
|
* The access flag {@code ACC_SYNTHETIC} with a mask value of
|
||||||
@ -237,41 +288,63 @@ public enum AccessFlag {
|
|||||||
* @see Executable#isSynthetic()
|
* @see Executable#isSynthetic()
|
||||||
* @see java.lang.module.ModuleDescriptor.Modifier#SYNTHETIC
|
* @see java.lang.module.ModuleDescriptor.Modifier#SYNTHETIC
|
||||||
*/
|
*/
|
||||||
SYNTHETIC(Modifier.SYNTHETIC, false,
|
SYNTHETIC(Modifier.SYNTHETIC, false, Location.SET_SYNTHETIC_9,
|
||||||
Set.of(Location.CLASS, Location.FIELD, Location.METHOD,
|
cffv -> {
|
||||||
Location.INNER_CLASS, Location.METHOD_PARAMETER,
|
if (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 )
|
||||||
Location.MODULE, Location.MODULE_REQUIRES,
|
return Location.SET_SYNTHETIC_9;
|
||||||
Location.MODULE_EXPORTS, Location.MODULE_OPENS)),
|
else {
|
||||||
|
return
|
||||||
|
switch(cffv) {
|
||||||
|
case RELEASE_7 -> Location.SET_SYNTHETIC_7;
|
||||||
|
case RELEASE_8 -> Location.SET_SYNTHETIC_8;
|
||||||
|
default -> Location.EMPTY_SET;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_ANNOTATION} with a mask value of
|
* The access flag {@code ACC_ANNOTATION} with a mask value of
|
||||||
* <code>{@value "0x%04x" Modifier#ANNOTATION}</code>.
|
* <code>{@value "0x%04x" Modifier#ANNOTATION}</code>.
|
||||||
* @see Class#isAnnotation()
|
* @see Class#isAnnotation()
|
||||||
*/
|
*/
|
||||||
ANNOTATION(Modifier.ANNOTATION, false, Location.SET_CLASS_INNER_CLASS),
|
ANNOTATION(Modifier.ANNOTATION, false, Location.SET_CLASS_INNER_CLASS,
|
||||||
|
cffv -> {return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
|
||||||
|
Location.SET_CLASS_INNER_CLASS:
|
||||||
|
Location.EMPTY_SET;}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_ENUM} with a mask value of
|
* The access flag {@code ACC_ENUM} with a mask value of
|
||||||
* <code>{@value "0x%04x" Modifier#ENUM}</code>.
|
* <code>{@value "0x%04x" Modifier#ENUM}</code>.
|
||||||
* @see Class#isEnum()
|
* @see Class#isEnum()
|
||||||
*/
|
*/
|
||||||
ENUM(Modifier.ENUM, false,
|
ENUM(Modifier.ENUM, false, Location.SET_CLASS_FIELD_INNER_CLASS,
|
||||||
Set.of(Location.CLASS, Location.FIELD, Location.INNER_CLASS)),
|
cffv -> {return (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) >= 0 ) ?
|
||||||
|
Location.SET_CLASS_FIELD_INNER_CLASS:
|
||||||
|
Location.EMPTY_SET;}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_MANDATED} with a mask value of
|
* The access flag {@code ACC_MANDATED} with a mask value of
|
||||||
* <code>{@value "0x%04x" Modifier#MANDATED}</code>.
|
* <code>{@value "0x%04x" Modifier#MANDATED}</code>.
|
||||||
*/
|
*/
|
||||||
MANDATED(Modifier.MANDATED, false,
|
MANDATED(Modifier.MANDATED, false, Location.SET_MANDATED_9,
|
||||||
Set.of(Location.METHOD_PARAMETER,
|
cffv -> {
|
||||||
Location.MODULE, Location.MODULE_REQUIRES,
|
if (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) {
|
||||||
Location.MODULE_EXPORTS, Location.MODULE_OPENS)),
|
return Location.SET_MANDATED_9;
|
||||||
|
} else {
|
||||||
|
return (cffv == ClassFileFormatVersion.RELEASE_8) ?
|
||||||
|
Location.SET_METHOD_PARAM:
|
||||||
|
Location.EMPTY_SET;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The access flag {@code ACC_MODULE} with a mask value of {@code
|
* The access flag {@code ACC_MODULE} with a mask value of {@code
|
||||||
* 0x8000}.
|
* 0x8000}.
|
||||||
*/
|
*/
|
||||||
MODULE(0x0000_8000, false, Location.SET_CLASS)
|
MODULE(0x0000_8000, false, Location.SET_CLASS,
|
||||||
|
cffv -> {return (cffv.compareTo(ClassFileFormatVersion.RELEASE_9) >= 0 ) ?
|
||||||
|
Location.SET_CLASS:
|
||||||
|
Location.EMPTY_SET;})
|
||||||
;
|
;
|
||||||
|
|
||||||
// May want to override toString for a different enum constant ->
|
// May want to override toString for a different enum constant ->
|
||||||
@ -283,11 +356,17 @@ public enum AccessFlag {
|
|||||||
// Intentionally using Set rather than EnumSet since EnumSet is
|
// Intentionally using Set rather than EnumSet since EnumSet is
|
||||||
// mutable.
|
// mutable.
|
||||||
private final Set<Location> locations;
|
private final Set<Location> locations;
|
||||||
|
// Lambda to implement locations(ClassFileFormatVersion cffv)
|
||||||
|
private final Function<ClassFileFormatVersion, Set<Location>> cffvToLocations;
|
||||||
|
|
||||||
private AccessFlag(int mask, boolean sourceModifier, Set<Location> locations) {
|
private AccessFlag(int mask,
|
||||||
|
boolean sourceModifier,
|
||||||
|
Set<Location> locations,
|
||||||
|
Function<ClassFileFormatVersion, Set<Location>> cffvToLocations) {
|
||||||
this.mask = mask;
|
this.mask = mask;
|
||||||
this.sourceModifier = sourceModifier;
|
this.sourceModifier = sourceModifier;
|
||||||
this.locations = locations;
|
this.locations = locations;
|
||||||
|
this.cffvToLocations = cffvToLocations;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -306,12 +385,27 @@ 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() {
|
public Set<Location> locations() {
|
||||||
return 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) {
|
||||||
|
if (cffvToLocations == null) {
|
||||||
|
return locations;
|
||||||
|
} else {
|
||||||
|
return cffvToLocations.apply(cffv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@return an unmodifiable set of access flags for the given mask value
|
* {@return an unmodifiable set of access flags for the given mask value
|
||||||
* appropriate for the location in question}
|
* appropriate for the location in question}
|
||||||
@ -402,15 +496,55 @@ public enum AccessFlag {
|
|||||||
MODULE_OPENS;
|
MODULE_OPENS;
|
||||||
|
|
||||||
// Repeated sets of locations used by AccessFlag constants
|
// Repeated sets of locations used by AccessFlag constants
|
||||||
|
private static final Set<Location> EMPTY_SET = Set.of();
|
||||||
|
private static final Set<Location> SET_MODULE = Set.of(MODULE);
|
||||||
|
private static final Set<Location> SET_CLASS_METHOD_INNER_CLASS =
|
||||||
|
Set.of(CLASS, METHOD, INNER_CLASS);
|
||||||
|
private static final Set<Location> SET_CLASS_FIELD_METHOD =
|
||||||
|
Set.of(CLASS, FIELD, METHOD);
|
||||||
|
private static final Set<Location> SET_CLASS_FIELD_INNER_CLASS =
|
||||||
|
Set.of(CLASS, FIELD, INNER_CLASS);
|
||||||
|
private static final Set<Location> SET_CLASS_FIELD_METHOD_INNER_CLASS =
|
||||||
|
Set.of(CLASS, FIELD, METHOD, INNER_CLASS);
|
||||||
|
private static final Set<Location> SET_CLASS_METHOD =
|
||||||
|
Set.of(CLASS, METHOD);
|
||||||
|
private static final Set<Location> SET_FIELD_METHOD =
|
||||||
|
Set.of(FIELD, METHOD);
|
||||||
private static final Set<Location> SET_FIELD_METHOD_INNER_CLASS =
|
private static final Set<Location> SET_FIELD_METHOD_INNER_CLASS =
|
||||||
Set.of(FIELD, METHOD, INNER_CLASS);
|
Set.of(FIELD, METHOD, INNER_CLASS);
|
||||||
private static final Set<Location> SET_METHOD = Set.of(METHOD);
|
private static final Set<Location> SET_METHOD = Set.of(METHOD);
|
||||||
|
private static final Set<Location> SET_METHOD_PARAM = Set.of(METHOD_PARAMETER);
|
||||||
private static final Set<Location> SET_FIELD = Set.of(FIELD);
|
private static final Set<Location> SET_FIELD = Set.of(FIELD);
|
||||||
private static final Set<Location> SET_CLASS = Set.of(CLASS);
|
private static final Set<Location> SET_CLASS = Set.of(CLASS);
|
||||||
private static final Set<Location> SET_CLASS_INNER_CLASS =
|
private static final Set<Location> SET_CLASS_INNER_CLASS =
|
||||||
Set.of(CLASS, INNER_CLASS);
|
Set.of(CLASS, INNER_CLASS);
|
||||||
private static final Set<Location> SET_MODULE_REQUIRES =
|
private static final Set<Location> SET_MODULE_REQUIRES =
|
||||||
Set.of(MODULE_REQUIRES);
|
Set.of(MODULE_REQUIRES);
|
||||||
|
private static final Set<Location> SET_PUBLIC_1 =
|
||||||
|
Set.of(CLASS, FIELD, METHOD, INNER_CLASS);
|
||||||
|
private static final Set<Location> SET_FINAL_8 =
|
||||||
|
Set.of(CLASS, FIELD, METHOD,
|
||||||
|
INNER_CLASS, /* added in 1.1 */
|
||||||
|
METHOD_PARAMETER); /* added in 8 */
|
||||||
|
private static final Set<Location> SET_SYNTHETIC_7 =
|
||||||
|
Set.of(CLASS, FIELD, METHOD,
|
||||||
|
INNER_CLASS);
|
||||||
|
private static final Set<Location> SET_SYNTHETIC_8 =
|
||||||
|
Set.of(CLASS, FIELD, METHOD,
|
||||||
|
INNER_CLASS, METHOD_PARAMETER);
|
||||||
|
private static final Set<Location> SET_SYNTHETIC_9 =
|
||||||
|
// Added as an access flag in 7
|
||||||
|
Set.of(CLASS, FIELD, METHOD,
|
||||||
|
INNER_CLASS,
|
||||||
|
METHOD_PARAMETER, // Added in 8
|
||||||
|
// Module-related items added in 9
|
||||||
|
MODULE, MODULE_REQUIRES,
|
||||||
|
MODULE_EXPORTS, MODULE_OPENS);
|
||||||
|
private static final Set<Location> SET_MANDATED_9 =
|
||||||
|
Set.of(METHOD_PARAMETER, // From 8
|
||||||
|
// Starting in 9
|
||||||
|
MODULE, MODULE_REQUIRES,
|
||||||
|
MODULE_EXPORTS, MODULE_OPENS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LocationToFlags {
|
private static class LocationToFlags {
|
||||||
|
@ -0,0 +1,353 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022, 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. Oracle designates this
|
||||||
|
* particular file as subject to the "Classpath" exception as provided
|
||||||
|
* by Oracle in the LICENSE file that accompanied this code.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Note to maintainers: when adding constants for newer releases,
|
||||||
|
// the implementation of latest() must be updated too.
|
||||||
|
|
||||||
|
private final 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];
|
||||||
|
}
|
||||||
|
}
|
@ -40,6 +40,7 @@ import java.util.HashSet;
|
|||||||
* model future releases of the language.
|
* model future releases of the language.
|
||||||
*
|
*
|
||||||
* @since 1.6
|
* @since 1.6
|
||||||
|
* @see java.lang.reflect.ClassFileFormatVersion
|
||||||
*/
|
*/
|
||||||
public enum SourceVersion {
|
public enum SourceVersion {
|
||||||
/*
|
/*
|
||||||
|
@ -66,8 +66,7 @@ public class ClassFileVersionTest {
|
|||||||
m = cl.getDeclaredMethod("getClassFileVersion", new Class[0]);
|
m = cl.getDeclaredMethod("getClassFileVersion", new Class[0]);
|
||||||
m.setAccessible(true);
|
m.setAccessible(true);
|
||||||
|
|
||||||
// Class file version is stored like "64.0".
|
int latestMajor = ClassFileFormatVersion.latest().major();
|
||||||
int latestMajor = (int)Double.parseDouble(System.getProperty("java.class.version"));
|
|
||||||
|
|
||||||
testIt(Object.class, latestMajor);
|
testIt(Object.class, latestMajor);
|
||||||
// ClassFileVersionTest use preview features so its minor version should be 0xFFFF
|
// ClassFileVersionTest use preview features so its minor version should be 0xFFFF
|
||||||
|
@ -34,7 +34,7 @@ import java.lang.reflect.*;
|
|||||||
* Field modifiers include:
|
* Field modifiers include:
|
||||||
* public, private, protected, static, final, volatile, transient,
|
* public, private, protected, static, final, volatile, transient,
|
||||||
*
|
*
|
||||||
* Additionall, the access flags enum and synthetic cannot be
|
* Additionally, the access flags enum and synthetic cannot be
|
||||||
* explicitly applied.
|
* explicitly applied.
|
||||||
*/
|
*/
|
||||||
public class FieldAccessFlagTest {
|
public class FieldAccessFlagTest {
|
||||||
|
@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8289106
|
||||||
|
* @summary Tests of AccessFlag.locations(ClassFileFormatVersion)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.reflect.AccessFlag;
|
||||||
|
import static java.lang.reflect.AccessFlag.*;
|
||||||
|
import java.lang.reflect.ClassFileFormatVersion;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There are several patterns of access flag applicability. First, an
|
||||||
|
* access flag can be applied to the same set of locations for each
|
||||||
|
* class file format version. This is "invariant" usage. Second, an
|
||||||
|
* access flag can be defined for version N, therefore inapplicable
|
||||||
|
* for earlier versions, and then applied to the same locations for
|
||||||
|
* all subsequent versions. This is "step" usage. Finally, an access
|
||||||
|
* flag to have a more complicated pattern, having multiple steps of
|
||||||
|
* being allowed at more locations or even having locations removed if
|
||||||
|
* the access flag is retired.
|
||||||
|
*
|
||||||
|
* List of access flags and how they are tested:
|
||||||
|
*
|
||||||
|
* PUBLIC step
|
||||||
|
* PRIVATE step
|
||||||
|
* PROTECTED step
|
||||||
|
* STATIC step
|
||||||
|
* FINAL two-step
|
||||||
|
* SUPER invariant
|
||||||
|
* OPEN step
|
||||||
|
* TRANSITIVE step
|
||||||
|
* SYNCHRONIZED invariant
|
||||||
|
* STATIC_PHASE step
|
||||||
|
* VOLATILE invariant
|
||||||
|
* BRIDGE step
|
||||||
|
* TRANSIENT invariant
|
||||||
|
* VARARGS step
|
||||||
|
* NATIVE invariant
|
||||||
|
* INTERFACE step
|
||||||
|
* ABSTRACT step
|
||||||
|
* STRICT other
|
||||||
|
* SYNTHETIC other (three-step)
|
||||||
|
* ANNOTATION step
|
||||||
|
* ENUM step
|
||||||
|
* MANDATED two-step
|
||||||
|
* MODULE step
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class VersionedLocationsTest {
|
||||||
|
public static void main(String... args) throws Exception {
|
||||||
|
testInvariantAccessFlags();
|
||||||
|
testStepFunctionAccessFlags();
|
||||||
|
testTwoStepAccessFlags();
|
||||||
|
testSynthetic();
|
||||||
|
testStrict();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invariant access flags have the same set of locations for each
|
||||||
|
* class file format version.
|
||||||
|
*/
|
||||||
|
private static void testInvariantAccessFlags() {
|
||||||
|
Set<AccessFlag> invariantAccessFlags =
|
||||||
|
Set.of(SUPER, SYNCHRONIZED, VOLATILE, TRANSIENT, NATIVE);
|
||||||
|
for(var accessFlag : invariantAccessFlags) {
|
||||||
|
Set<AccessFlag.Location> expected = accessFlag.locations();
|
||||||
|
|
||||||
|
for(var cffv : ClassFileFormatVersion.values()) {
|
||||||
|
compareLocations(accessFlag.locations(), accessFlag, cffv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testStepFunctionAccessFlags() {
|
||||||
|
StepFunctionTC[] testCases = {
|
||||||
|
new StepFunctionTC(PUBLIC,
|
||||||
|
removeInnerClass(PUBLIC.locations()),
|
||||||
|
ClassFileFormatVersion.RELEASE_1),
|
||||||
|
|
||||||
|
new StepFunctionTC(PRIVATE,
|
||||||
|
removeInnerClass(PRIVATE.locations()),
|
||||||
|
ClassFileFormatVersion.RELEASE_1),
|
||||||
|
|
||||||
|
new StepFunctionTC(PROTECTED,
|
||||||
|
removeInnerClass(PROTECTED.locations()),
|
||||||
|
ClassFileFormatVersion.RELEASE_1),
|
||||||
|
|
||||||
|
new StepFunctionTC(STATIC,
|
||||||
|
removeInnerClass(STATIC.locations()),
|
||||||
|
ClassFileFormatVersion.RELEASE_1),
|
||||||
|
|
||||||
|
new StepFunctionTC(OPEN,
|
||||||
|
Set.of(),
|
||||||
|
ClassFileFormatVersion.RELEASE_9),
|
||||||
|
|
||||||
|
new StepFunctionTC(TRANSITIVE,
|
||||||
|
Set.of(),
|
||||||
|
ClassFileFormatVersion.RELEASE_9),
|
||||||
|
|
||||||
|
new StepFunctionTC(STATIC_PHASE,
|
||||||
|
Set.of(),
|
||||||
|
ClassFileFormatVersion.RELEASE_9),
|
||||||
|
|
||||||
|
new StepFunctionTC(BRIDGE,
|
||||||
|
Set.of(),
|
||||||
|
ClassFileFormatVersion.RELEASE_5),
|
||||||
|
|
||||||
|
new StepFunctionTC(VARARGS,
|
||||||
|
Set.of(),
|
||||||
|
ClassFileFormatVersion.RELEASE_5),
|
||||||
|
|
||||||
|
new StepFunctionTC(INTERFACE,
|
||||||
|
removeInnerClass(INTERFACE.locations()),
|
||||||
|
ClassFileFormatVersion.RELEASE_1),
|
||||||
|
|
||||||
|
new StepFunctionTC(ABSTRACT,
|
||||||
|
removeInnerClass(ABSTRACT.locations()),
|
||||||
|
ClassFileFormatVersion.RELEASE_1),
|
||||||
|
|
||||||
|
new StepFunctionTC(ANNOTATION,
|
||||||
|
Set.of(),
|
||||||
|
ClassFileFormatVersion.RELEASE_5),
|
||||||
|
|
||||||
|
new StepFunctionTC(ENUM,
|
||||||
|
Set.of(),
|
||||||
|
ClassFileFormatVersion.RELEASE_5),
|
||||||
|
|
||||||
|
new StepFunctionTC(MODULE,
|
||||||
|
Set.of(),
|
||||||
|
ClassFileFormatVersion.RELEASE_9)
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var testCase : testCases) {
|
||||||
|
for (var cffv : ClassFileFormatVersion.values()) {
|
||||||
|
compareLocations(cffv.compareTo(testCase.transition()) >= 0 ?
|
||||||
|
testCase.finalLocs() :
|
||||||
|
testCase.initialLocs(),
|
||||||
|
testCase.accessFlag, cffv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void compareLocations(Set<AccessFlag.Location> expected,
|
||||||
|
AccessFlag accessFlag,
|
||||||
|
ClassFileFormatVersion cffv) {
|
||||||
|
var actual = accessFlag.locations(cffv);
|
||||||
|
if (!expected.equals(actual)) {
|
||||||
|
throw new RuntimeException("Unexpected locations for " +
|
||||||
|
accessFlag + " on " + cffv + "\n" +
|
||||||
|
"Expected " + expected + "; got \t" + actual);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<AccessFlag.Location> removeInnerClass(Set<AccessFlag.Location> locations) {
|
||||||
|
var s = new HashSet<>(locations);
|
||||||
|
s.remove(Location.INNER_CLASS);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private record StepFunctionTC(AccessFlag accessFlag,
|
||||||
|
Set<AccessFlag.Location> initialLocs,
|
||||||
|
ClassFileFormatVersion transition) {
|
||||||
|
|
||||||
|
public Set<AccessFlag.Location> finalLocs() {
|
||||||
|
return accessFlag.locations();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private record TwoStepFunctionTC(AccessFlag accessFlag,
|
||||||
|
Set<AccessFlag.Location> initialLocs,
|
||||||
|
ClassFileFormatVersion transition1,
|
||||||
|
Set<AccessFlag.Location> firstLocs,
|
||||||
|
ClassFileFormatVersion transition2) {
|
||||||
|
|
||||||
|
public Set<AccessFlag.Location> secondLocs() {
|
||||||
|
return accessFlag.locations();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testTwoStepAccessFlags() {
|
||||||
|
TwoStepFunctionTC[] testCases = {
|
||||||
|
new TwoStepFunctionTC(FINAL,
|
||||||
|
Set.of(Location.CLASS, Location.FIELD, Location.METHOD),
|
||||||
|
ClassFileFormatVersion.RELEASE_1,
|
||||||
|
Set.of(Location.CLASS, Location.FIELD, Location.METHOD, Location.INNER_CLASS),
|
||||||
|
ClassFileFormatVersion.RELEASE_8),
|
||||||
|
|
||||||
|
new TwoStepFunctionTC(MANDATED,
|
||||||
|
Set.of(),
|
||||||
|
ClassFileFormatVersion.RELEASE_8,
|
||||||
|
Set.of(Location.METHOD_PARAMETER),
|
||||||
|
ClassFileFormatVersion.RELEASE_9),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var testCase : testCases) {
|
||||||
|
for (var cffv : ClassFileFormatVersion.values()) {
|
||||||
|
var transition1 = testCase.transition1();
|
||||||
|
var transition2 = testCase.transition2();
|
||||||
|
Set<AccessFlag.Location> expected;
|
||||||
|
if (cffv.compareTo(transition1) < 0) {
|
||||||
|
expected = testCase.initialLocs();
|
||||||
|
} else if (cffv.compareTo(transition1) >= 0 &&
|
||||||
|
cffv.compareTo(transition2) < 0) {
|
||||||
|
expected = testCase.firstLocs();
|
||||||
|
} else { // cffv >= transition2
|
||||||
|
expected = testCase.secondLocs();
|
||||||
|
}
|
||||||
|
|
||||||
|
compareLocations(expected, testCase.accessFlag(), cffv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testSynthetic() {
|
||||||
|
for (var cffv : ClassFileFormatVersion.values()) {
|
||||||
|
Set<AccessFlag.Location> expected;
|
||||||
|
if (cffv.compareTo(ClassFileFormatVersion.RELEASE_6) <= 0) {
|
||||||
|
expected = Set.of();
|
||||||
|
} else {
|
||||||
|
expected =
|
||||||
|
switch(cffv) {
|
||||||
|
case RELEASE_7 -> Set.of(Location.CLASS, Location.FIELD,
|
||||||
|
Location.METHOD,
|
||||||
|
Location.INNER_CLASS);
|
||||||
|
case RELEASE_8 -> Set.of(Location.CLASS, Location.FIELD,
|
||||||
|
Location.METHOD,
|
||||||
|
Location.INNER_CLASS,
|
||||||
|
Location.METHOD_PARAMETER);
|
||||||
|
default -> SYNTHETIC.locations();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
compareLocations(expected, SYNTHETIC, cffv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testStrict() {
|
||||||
|
for (var cffv : ClassFileFormatVersion.values()) {
|
||||||
|
Set<AccessFlag.Location> expected =
|
||||||
|
(cffv.compareTo(ClassFileFormatVersion.RELEASE_2) >= 0 &&
|
||||||
|
cffv.compareTo(ClassFileFormatVersion.RELEASE_16) <= 0) ?
|
||||||
|
Set.of(Location.METHOD) :
|
||||||
|
Set.of();
|
||||||
|
compareLocations(expected, STRICT, cffv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user