>> historicalLocations) {
this.mask = mask;
this.sourceModifier = sourceModifier;
this.locations = locations;
- this.cffvToLocations = cffvToLocations;
+ this.historicalLocations = Location.ensureHistoryOrdered(historicalLocations);
}
/**
- * {@return the corresponding integer mask for the access flag}
+ * {@return the corresponding mask for the access flag} The mask has
+ * exactly one bit set and is in the range of {@code char}.
*/
public int mask() {
return mask;
}
/**
- * {@return whether or not the flag has a directly corresponding
+ * {@return whether or not this flag has a directly corresponding
* modifier in the Java programming language}
*/
public boolean sourceModifier() {
@@ -457,26 +346,28 @@ public enum AccessFlag {
}
/**
- * {@return kinds of constructs the flag can be applied to in the
- * latest class file format version}
+ * {@return locations this flag can be applied to in the current class file
+ * format version}
+ *
+ * This method returns an empty set if this flag is not defined in
+ * the current class file format version.
*/
public Set locations() {
return locations;
}
/**
- * {@return kinds of constructs the flag can be applied to in the
- * given class file format version}
+ * {@return locations this flag can be applied to in the given class file
+ * format version}
+ *
+ * This method returns an empty set if this flag is not defined in
+ * the given {@code cffv}.
+ *
* @param cffv the class file format version to use
* @throws NullPointerException if the parameter is {@code null}
*/
public Set locations(ClassFileFormatVersion cffv) {
- Objects.requireNonNull(cffv);
- if (cffvToLocations == null) {
- return locations;
- } else {
- return cffvToLocations.apply(cffv);
- }
+ return Location.findInHistory(locations, historicalLocations, cffv);
}
/**
@@ -489,84 +380,160 @@ public enum AccessFlag {
* positions not support for the location in question
*/
public static Set maskToAccessFlags(int mask, Location location) {
- Set result = java.util.EnumSet.noneOf(AccessFlag.class);
- for (var accessFlag : LocationToFlags.locationToFlags.get(location)) {
- int accessMask = accessFlag.mask();
- if ((mask & accessMask) != 0) {
- result.add(accessFlag);
- mask = mask & ~accessMask;
- }
- }
- if (mask != 0) {
+ var definition = findDefinition(location);
+ int flagsMask = location.flagsMask();
+ int parsingMask = location == Location.METHOD ? flagsMask | ACC_STRICT : flagsMask; // flagMask lacks strictfp
+ int unmatchedMask = mask & (~parsingMask);
+ if (unmatchedMask != 0) {
throw new IllegalArgumentException("Unmatched bit position 0x" +
- Integer.toHexString(mask) +
- " for location " + location);
+ Integer.toHexString(unmatchedMask) +
+ " for location " + location);
}
- return Collections.unmodifiableSet(result);
+ return new AccessFlagSet(definition, mask);
}
/**
- * A location within a class file where flags can be applied.
- *
- * Note that since these locations represent class file structures
- * rather than language structures many language structures, such
+ * A location within a {@code class} file where flags can be applied.
+ *
+ * Note that since these locations represent {@code class} file structures
+ * rather than language structures, many language structures, such
* as constructors and interfaces, are not present.
* @since 20
*/
public enum Location {
/**
* Class location.
- * @jvms 4.1 The ClassFile Structure
+ *
+ * @see Class#accessFlags()
+ * @see ClassModel#flags()
+ * @see Modifier#classModifiers()
+ * @see Modifier#interfaceModifiers()
+ * @jvms 4.1 The {@code ClassFile} Structure
*/
- CLASS,
+ CLASS(ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
+ ACC_INTERFACE | ACC_ABSTRACT |
+ ACC_SYNTHETIC | ACC_ANNOTATION |
+ ACC_ENUM | ACC_MODULE,
+ List.of(Map.entry(RELEASE_8, // no module
+ ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
+ ACC_INTERFACE | ACC_ABSTRACT |
+ ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM),
+ Map.entry(RELEASE_4, // no synthetic, annotation, enum
+ ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
+ ACC_INTERFACE | ACC_ABSTRACT))),
/**
* Field location.
+ *
+ * @see Field#accessFlags()
+ * @see FieldModel#flags()
+ * @see Modifier#fieldModifiers()
* @jvms 4.5 Fields
*/
- FIELD,
+ FIELD(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
+ ACC_STATIC | ACC_FINAL | ACC_VOLATILE |
+ ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM,
+ List.of(Map.entry(RELEASE_4, // no synthetic, enum
+ ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
+ ACC_STATIC | ACC_FINAL | ACC_VOLATILE |
+ ACC_TRANSIENT))),
/**
* Method location.
+ *
+ * @see Executable#accessFlags()
+ * @see MethodModel#flags()
+ * @see Modifier#methodModifiers()
+ * @see Modifier#constructorModifiers()
* @jvms 4.6 Methods
*/
- METHOD,
+ METHOD(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
+ ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
+ ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE |
+ ACC_ABSTRACT | ACC_SYNTHETIC,
+ List.of(Map.entry(RELEASE_16, // had strict
+ ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
+ ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
+ ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE |
+ ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC),
+ Map.entry(RELEASE_4, // no bridge, varargs, synthetic
+ ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
+ ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
+ ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT),
+ Map.entry(RELEASE_1, // no strict
+ ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
+ ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
+ ACC_NATIVE | ACC_ABSTRACT))),
/**
* Inner class location.
- * @jvms 4.7.6 The InnerClasses Attribute
+ *
+ * @see Class#accessFlags()
+ * @see InnerClassInfo#flags()
+ * @see Modifier#classModifiers()
+ * @see Modifier#interfaceModifiers()
+ * @jvms 4.7.6 The {@code InnerClasses} Attribute
*/
- INNER_CLASS,
+ INNER_CLASS(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
+ ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT |
+ ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM,
+ List.of(Map.entry(RELEASE_4, // no synthetic, annotation, enum
+ ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
+ ACC_STATIC | ACC_FINAL | ACC_INTERFACE |
+ ACC_ABSTRACT),
+ Map.entry(RELEASE_0, 0))), // did not exist
/**
* Method parameter location.
- * @jvms 4.7.24 The MethodParameters Attribute
+ *
+ * @see Parameter#accessFlags()
+ * @see MethodParameterInfo#flags()
+ * @see Modifier#parameterModifiers()
+ * @jvms 4.7.24 The {@code MethodParameters} Attribute
*/
- METHOD_PARAMETER,
+ METHOD_PARAMETER(ACC_FINAL | ACC_SYNTHETIC | ACC_MANDATED,
+ List.of(Map.entry(RELEASE_7, 0))), // did not exist
/**
- * Module location
- * @jvms 4.7.25 The Module Attribute
+ * Module location.
+ *
+ * @see ModuleDescriptor#accessFlags()
+ * @see ModuleAttribute#moduleFlags()
+ * @jvms 4.7.25 The {@code Module} Attribute
*/
- MODULE,
+ MODULE(ACC_OPEN | ACC_SYNTHETIC | ACC_MANDATED,
+ List.of(Map.entry(RELEASE_8, 0))), // did not exist
/**
- * Module requires location
- * @jvms 4.7.25 The Module Attribute
+ * Module requires location.
+ *
+ * @see ModuleDescriptor.Requires#accessFlags()
+ * @see ModuleRequireInfo#requiresFlags()
+ * @jvms 4.7.25 The {@code Module} Attribute
*/
- MODULE_REQUIRES,
+ MODULE_REQUIRES(ACC_TRANSITIVE | ACC_STATIC_PHASE | ACC_SYNTHETIC | ACC_MANDATED,
+ List.of(Map.entry(RELEASE_8, 0))), // did not exist
/**
- * Module exports location
- * @jvms 4.7.25 The Module Attribute
+ * Module exports location.
+ *
+ * @see ModuleDescriptor.Exports#accessFlags()
+ * @see ModuleExportInfo#exportsFlags()
+ * @jvms 4.7.25 The {@code Module} Attribute
*/
- MODULE_EXPORTS,
+ MODULE_EXPORTS(ACC_SYNTHETIC | ACC_MANDATED,
+ List.of(Map.entry(RELEASE_8, 0))), // did not exist
/**
- * Module opens location
- * @jvms 4.7.25 The Module Attribute
+ * Module opens location.
+ *
+ * @see ModuleDescriptor.Opens#accessFlags()
+ * @see ModuleOpenInfo#opensFlags()
+ * @jvms 4.7.25 The {@code Module} Attribute
*/
- MODULE_OPENS;
+ MODULE_OPENS(ACC_SYNTHETIC | ACC_MANDATED,
+ List.of(Map.entry(RELEASE_8, 0))), // did not exist
+ ;
// Repeated sets of locations used by AccessFlag constants
private static final Set EMPTY_SET = Set.of();
@@ -593,20 +560,18 @@ public enum AccessFlag {
Set.of(CLASS, INNER_CLASS);
private static final Set SET_MODULE_REQUIRES =
Set.of(MODULE_REQUIRES);
- private static final Set SET_PUBLIC_1 =
- Set.of(CLASS, FIELD, METHOD, INNER_CLASS);
private static final Set SET_FINAL_8 =
Set.of(CLASS, FIELD, METHOD,
INNER_CLASS, /* added in 1.1 */
METHOD_PARAMETER); /* added in 8 */
- private static final Set SET_SYNTHETIC_7 =
+ private static final Set SET_SYNTHETIC_5 =
Set.of(CLASS, FIELD, METHOD,
INNER_CLASS);
private static final Set SET_SYNTHETIC_8 =
Set.of(CLASS, FIELD, METHOD,
INNER_CLASS, METHOD_PARAMETER);
private static final Set SET_SYNTHETIC_9 =
- // Added as an access flag in 7
+ // Added as an access flag in 5.0
Set.of(CLASS, FIELD, METHOD,
INNER_CLASS,
METHOD_PARAMETER, // Added in 8
@@ -618,37 +583,227 @@ public enum AccessFlag {
// Starting in 9
MODULE, MODULE_REQUIRES,
MODULE_EXPORTS, MODULE_OPENS);
+
+ private final int flagsMask;
+ private final List> historicalFlagsMasks;
+
+ Location(int flagsMask,
+ List> historicalFlagsMasks) {
+ this.flagsMask = flagsMask;
+ this.historicalFlagsMasks = ensureHistoryOrdered(historicalFlagsMasks);
+ }
+
+ // Ensures the historical versions are from newest to oldest and do not include the latest
+ // These 2 utilities reside in Location because Location must be initialized before AccessFlag
+ private static List> ensureHistoryOrdered(
+ List> history) {
+ ClassFileFormatVersion lastVersion = ClassFileFormatVersion.latest();
+ for (var e : history) {
+ var historyVersion = e.getKey();
+ if (lastVersion.compareTo(historyVersion) <= 0) {
+ throw new IllegalArgumentException("Versions out of order");
+ }
+ lastVersion = historyVersion;
+ }
+ return history;
+ }
+
+ private static T findInHistory(T candidate, List> history,
+ ClassFileFormatVersion cffv) {
+ Objects.requireNonNull(cffv);
+ for (var e : history) {
+ if (e.getKey().compareTo(cffv) < 0) {
+ // last version found was valid
+ return candidate;
+ }
+ candidate = e.getValue();
+ }
+ return candidate;
+ }
+
+ /**
+ * {@return the union of masks of all access flags defined for
+ * this location in the current class file format version}
+ *
+ * This method returns {@code 0} if this location does not exist in
+ * the current class file format version.
+ *
+ * @since 25
+ */
+ public int flagsMask() {
+ return flagsMask;
+ }
+
+ /**
+ * {@return the union of masks of all access flags defined for
+ * this location in the given class file format version}
+ *
+ * This method returns {@code 0} if this location does not exist in
+ * the given {@code cffv}.
+ *
+ * @param cffv the class file format version
+ * @throws NullPointerException if {@code cffv} is {@code null}
+ * @since 25
+ */
+ public int flagsMask(ClassFileFormatVersion cffv) {
+ return findInHistory(flagsMask, historicalFlagsMasks, cffv);
+ }
+
+ /**
+ * {@return the set of access flags defined for this location in the
+ * current class file format version} The set is immutable.
+ *
+ * This method returns an empty set if this location does not exist
+ * in the current class file format version.
+ *
+ * @since 25
+ */
+ public Set flags() {
+ return new AccessFlagSet(findDefinition(this), flagsMask());
+ }
+
+ /**
+ * {@return the set of access flags defined for this location in the
+ * given class file format version} The set is immutable.
+ *
+ * This method returns an empty set if this location does not exist
+ * in the given {@code cffv}.
+ *
+ * @param cffv the class file format version
+ * @throws NullPointerException if {@code cffv} is {@code null}
+ * @since 25
+ */
+ public Set flags(ClassFileFormatVersion cffv) {
+ // implicit null check cffv
+ return new AccessFlagSet(findDefinition(this), flagsMask(cffv));
+ }
}
- private static class LocationToFlags {
- private static Map> locationToFlags =
- Map.ofEntries(entry(Location.CLASS,
- Set.of(PUBLIC, FINAL, SUPER,
- INTERFACE, ABSTRACT,
- SYNTHETIC, ANNOTATION,
- ENUM, AccessFlag.MODULE)),
- entry(Location.FIELD,
- Set.of(PUBLIC, PRIVATE, PROTECTED,
- STATIC, FINAL, VOLATILE,
- TRANSIENT, SYNTHETIC, ENUM)),
- entry(Location.METHOD,
- Set.of(PUBLIC, PRIVATE, PROTECTED,
- STATIC, FINAL, SYNCHRONIZED,
- BRIDGE, VARARGS, NATIVE,
- ABSTRACT, STRICT, SYNTHETIC)),
- entry(Location.INNER_CLASS,
- Set.of(PUBLIC, PRIVATE, PROTECTED,
- STATIC, FINAL, INTERFACE, ABSTRACT,
- SYNTHETIC, ANNOTATION, ENUM)),
- entry(Location.METHOD_PARAMETER,
- Set.of(FINAL, SYNTHETIC, MANDATED)),
- entry(Location.MODULE,
- Set.of(OPEN, SYNTHETIC, MANDATED)),
- entry(Location.MODULE_REQUIRES,
- Set.of(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED)),
- entry(Location.MODULE_EXPORTS,
- Set.of(SYNTHETIC, MANDATED)),
- entry(Location.MODULE_OPENS,
- Set.of(SYNTHETIC, MANDATED)));
+ private static AccessFlag[] createDefinition(AccessFlag... known) {
+ var ret = new AccessFlag[Character.SIZE];
+ for (var flag : known) {
+ var mask = flag.mask;
+ int pos = Integer.numberOfTrailingZeros(mask);
+ assert ret[pos] == null : ret[pos] + " " + flag;
+ ret[pos] = flag;
+ }
+ return ret;
+ }
+
+ // Will take extra args in the future for valhalla switch
+ private static AccessFlag[] findDefinition(Location location) {
+ return switch (location) {
+ case CLASS -> CLASS_FLAGS;
+ case FIELD -> FIELD_FLAGS;
+ case METHOD -> METHOD_FLAGS;
+ case INNER_CLASS -> INNER_CLASS_FLAGS;
+ case METHOD_PARAMETER -> METHOD_PARAMETER_FLAGS;
+ case MODULE -> MODULE_FLAGS;
+ case MODULE_REQUIRES -> MODULE_REQUIRES_FLAGS;
+ case MODULE_EXPORTS -> MODULE_EXPORTS_FLAGS;
+ case MODULE_OPENS -> MODULE_OPENS_FLAGS;
+ };
+ }
+
+ private static final @Stable AccessFlag[] // Can use stable array and lazy init in the future
+ CLASS_FLAGS = createDefinition(PUBLIC, FINAL, SUPER, INTERFACE, ABSTRACT, SYNTHETIC, ANNOTATION, ENUM, MODULE),
+ FIELD_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, VOLATILE, TRANSIENT, SYNTHETIC, ENUM),
+ METHOD_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, SYNCHRONIZED, BRIDGE, VARARGS, NATIVE, ABSTRACT, STRICT, SYNTHETIC),
+ INNER_CLASS_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, INTERFACE, ABSTRACT, SYNTHETIC, ANNOTATION, ENUM),
+ METHOD_PARAMETER_FLAGS = createDefinition(FINAL, SYNTHETIC, MANDATED),
+ MODULE_FLAGS = createDefinition(OPEN, SYNTHETIC, MANDATED),
+ MODULE_REQUIRES_FLAGS = createDefinition(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED),
+ MODULE_EXPORTS_FLAGS = createDefinition(SYNTHETIC, MANDATED),
+ MODULE_OPENS_FLAGS = createDefinition(SYNTHETIC, MANDATED);
+
+ private static int undefinedMask(AccessFlag[] definition, int mask) {
+ assert definition.length == Character.SIZE;
+ int definedMask = 0;
+ for (int i = 0; i < Character.SIZE; i++) {
+ if (definition[i] != null) {
+ definedMask |= 1 << i;
+ }
+ }
+ return mask & ~definedMask;
+ }
+
+ private static final class AccessFlagSet extends AbstractSet {
+ private final @Stable AccessFlag[] definition;
+ private final int mask;
+
+ // all mutating methods throw UnsupportedOperationException
+ @Override public boolean add(AccessFlag e) { throw uoe(); }
+ @Override public boolean addAll(Collection extends AccessFlag> c) { throw uoe(); }
+ @Override public void clear() { throw uoe(); }
+ @Override public boolean remove(Object o) { throw uoe(); }
+ @Override public boolean removeAll(Collection> c) { throw uoe(); }
+ @Override public boolean removeIf(Predicate super AccessFlag> filter) { throw uoe(); }
+ @Override public boolean retainAll(Collection> c) { throw uoe(); }
+ private static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
+
+ private AccessFlagSet(AccessFlag[] definition, int mask) {
+ assert undefinedMask(definition, mask) == 0 : mask;
+ this.definition = definition;
+ this.mask = mask;
+ }
+
+ @Override
+ public Iterator iterator() {
+ return new AccessFlagIterator(definition, mask);
+ }
+
+ @Override
+ public void forEach(Consumer super AccessFlag> action) {
+ Objects.requireNonNull(action); // in case of empty
+ for (int i = 0; i < Character.SIZE; i++) {
+ if ((mask & (1 << i)) != 0) {
+ action.accept(definition[i]);
+ }
+ }
+ }
+
+ private static final class AccessFlagIterator implements Iterator {
+ private final @Stable AccessFlag[] definition;
+ private int remainingMask;
+
+ private AccessFlagIterator(AccessFlag[] definition, int remainingMask) {
+ this.definition = definition;
+ this.remainingMask = remainingMask;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return remainingMask != 0;
+ }
+
+ @Override
+ public AccessFlag next() {
+ int flagBit = Integer.lowestOneBit(remainingMask);
+ if (flagBit == 0) {
+ throw new NoSuchElementException();
+ }
+ remainingMask &= ~flagBit;
+ return definition[Integer.numberOfTrailingZeros(flagBit)];
+ }
+ }
+
+ @Override
+ public int size() {
+ return Integer.bitCount(mask);
+ }
+
+ @Override
+ public boolean contains(Object o) {
+ if (Objects.requireNonNull(o) instanceof AccessFlag flag) {
+ int bit = flag.mask;
+ return (bit & mask) != 0 && definition[Integer.numberOfTrailingZeros(bit)] == flag;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return mask == 0;
+ }
}
}
diff --git a/src/java.base/share/classes/java/lang/reflect/Modifier.java b/src/java.base/share/classes/java/lang/reflect/Modifier.java
index 1b7bc3bf65b..624f32b4e04 100644
--- a/src/java.base/share/classes/java/lang/reflect/Modifier.java
+++ b/src/java.base/share/classes/java/lang/reflect/Modifier.java
@@ -448,6 +448,8 @@ public final class Modifier {
* @return an {@code int} value OR-ing together the source language
* modifiers that can be applied to a class.
*
+ * @see AccessFlag.Location#CLASS
+ * @see AccessFlag.Location#INNER_CLASS
* @jls 8.1.1 Class Modifiers
* @since 1.7
*/
@@ -461,6 +463,8 @@ public final class Modifier {
* @return an {@code int} value OR-ing together the source language
* modifiers that can be applied to an interface.
*
+ * @see AccessFlag.Location#CLASS
+ * @see AccessFlag.Location#INNER_CLASS
* @jls 9.1.1 Interface Modifiers
* @since 1.7
*/
@@ -474,6 +478,7 @@ public final class Modifier {
* @return an {@code int} value OR-ing together the source language
* modifiers that can be applied to a constructor.
*
+ * @see AccessFlag.Location#METHOD
* @jls 8.8.3 Constructor Modifiers
* @since 1.7
*/
@@ -487,6 +492,7 @@ public final class Modifier {
* @return an {@code int} value OR-ing together the source language
* modifiers that can be applied to a method.
*
+ * @see AccessFlag.Location#METHOD
* @jls 8.4.3 Method Modifiers
* @since 1.7
*/
@@ -500,6 +506,7 @@ public final class Modifier {
* @return an {@code int} value OR-ing together the source language
* modifiers that can be applied to a field.
*
+ * @see AccessFlag.Location#FIELD
* @jls 8.3.1 Field Modifiers
* @since 1.7
*/
@@ -513,6 +520,7 @@ public final class Modifier {
* @return an {@code int} value OR-ing together the source language
* modifiers that can be applied to a parameter.
*
+ * @see AccessFlag.Location#METHOD_PARAMETER
* @jls 8.4.1 Formal Parameters
* @since 1.8
*/
diff --git a/test/jdk/java/lang/reflect/AccessFlag/BasicAccessFlagTest.java b/test/jdk/java/lang/reflect/AccessFlag/BasicAccessFlagTest.java
index 12eeeb45c6e..d87f60a0a1a 100644
--- a/test/jdk/java/lang/reflect/AccessFlag/BasicAccessFlagTest.java
+++ b/test/jdk/java/lang/reflect/AccessFlag/BasicAccessFlagTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 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
@@ -158,5 +158,20 @@ public class BasicAccessFlagTest {
; // Expected
}
}
+
+ for (var location : AccessFlag.Location.values()) {
+ try {
+ location.flags(null);
+ throw new RuntimeException("Did not get NPE on " + location + ".flags(null)");
+ } catch (NullPointerException npe ) {
+ ; // Expected
+ }
+ try {
+ location.flagsMask(null);
+ throw new RuntimeException("Did not get NPE on " + location + ".flagsMask(null)");
+ } catch (NullPointerException npe ) {
+ ; // Expected
+ }
+ }
}
}
diff --git a/test/jdk/java/lang/reflect/AccessFlag/ClassAccessFlagTest.java b/test/jdk/java/lang/reflect/AccessFlag/ClassAccessFlagTest.java
index 10ebfd6aff2..1c80c29dc9b 100644
--- a/test/jdk/java/lang/reflect/AccessFlag/ClassAccessFlagTest.java
+++ b/test/jdk/java/lang/reflect/AccessFlag/ClassAccessFlagTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 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
@@ -31,6 +31,8 @@ import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
+import static java.lang.reflect.AccessFlag.*;
+
/*
* Class access flags that can directly or indirectly declared in
* source include:
@@ -47,7 +49,7 @@ import java.util.*;
* file. Therefore, this test does not attempt to probe the setting of
* that access flag.
*/
-@ExpectedClassFlags("[PUBLIC, FINAL, SUPER]")
+@ExpectedClassFlags({PUBLIC, FINAL, SUPER})
public final class ClassAccessFlagTest {
public static void main(String... args) {
// Top-level and auxiliary classes; i.e. non-inner classes
@@ -76,10 +78,12 @@ public final class ClassAccessFlagTest {
ExpectedClassFlags expected =
clazz.getAnnotation(ExpectedClassFlags.class);
if (expected != null) {
- String actual = clazz.accessFlags().toString();
- if (!expected.value().equals(actual)) {
+ Set base = EnumSet.noneOf(AccessFlag.class);
+ Collections.addAll(base, expected.value());
+ Set actual = clazz.accessFlags();
+ if (!base.equals(actual)) {
throw new RuntimeException("On " + clazz +
- " expected " + expected.value() +
+ " expected " + base +
" got " + actual);
}
}
@@ -98,7 +102,7 @@ public final class ClassAccessFlagTest {
void.class // same access flag rules
};
- var expected = Set.of(AccessFlag.PUBLIC,
+ var expected = Set.of(PUBLIC,
AccessFlag.FINAL,
AccessFlag.ABSTRACT);
@@ -127,8 +131,8 @@ public final class ClassAccessFlagTest {
for (var accessClass : accessClasses) {
AccessFlag accessLevel;
var flags = accessClass.accessFlags();
- if (flags.contains(AccessFlag.PUBLIC))
- accessLevel = AccessFlag.PUBLIC;
+ if (flags.contains(PUBLIC))
+ accessLevel = PUBLIC;
else if (flags.contains(AccessFlag.PROTECTED))
accessLevel = AccessFlag.PROTECTED;
else if (flags.contains(AccessFlag.PRIVATE))
@@ -145,7 +149,7 @@ public final class ClassAccessFlagTest {
}
} else {
if (containsAny(arrayClass.accessFlags(),
- Set.of(AccessFlag.PUBLIC,
+ Set.of(PUBLIC,
AccessFlag.PROTECTED,
AccessFlag.PRIVATE))) {
throw new RuntimeException("Unexpected access flags on " +
@@ -161,32 +165,32 @@ public final class ClassAccessFlagTest {
// PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, INTERFACE, ABSTRACT,
// SYNTHETIC, ANNOTATION, ENUM.
- @ExpectedClassFlags("[PUBLIC, STATIC, INTERFACE, ABSTRACT]")
+ @ExpectedClassFlags({PUBLIC, STATIC, INTERFACE, ABSTRACT})
public interface PublicInterface {}
- @ExpectedClassFlags("[PROTECTED, STATIC, INTERFACE, ABSTRACT]")
+ @ExpectedClassFlags({PROTECTED, STATIC, INTERFACE, ABSTRACT})
protected interface ProtectedInterface {}
- @ExpectedClassFlags("[PRIVATE, STATIC, INTERFACE, ABSTRACT]")
+ @ExpectedClassFlags({PRIVATE, STATIC, INTERFACE, ABSTRACT})
private interface PrivateInterface {}
- @ExpectedClassFlags("[STATIC, INTERFACE, ABSTRACT]")
+ @ExpectedClassFlags({STATIC, INTERFACE, ABSTRACT})
/*package*/ interface PackageInterface {}
- @ExpectedClassFlags("[FINAL]")
+ @ExpectedClassFlags({FINAL})
/*package*/ final class TestFinalClass {}
- @ExpectedClassFlags("[ABSTRACT]")
+ @ExpectedClassFlags({ABSTRACT})
/*package*/ abstract class TestAbstractClass {}
- @ExpectedClassFlags("[STATIC, INTERFACE, ABSTRACT, ANNOTATION]")
+ @ExpectedClassFlags({STATIC, INTERFACE, ABSTRACT, ANNOTATION})
/*package*/ @interface TestMarkerAnnotation {}
- @ExpectedClassFlags("[PUBLIC, STATIC, FINAL, ENUM]")
+ @ExpectedClassFlags({PUBLIC, STATIC, FINAL, ENUM})
public enum MetaSynVar {
QUUX;
}
// Is there is at least one special enum constant, the enum class
// itself is implicitly abstract rather than final.
- @ExpectedClassFlags("[PROTECTED, STATIC, ABSTRACT, ENUM]")
+ @ExpectedClassFlags({PROTECTED, STATIC, ABSTRACT, ENUM})
protected enum MetaSynVar2 {
WOMBAT{
@Override
@@ -195,24 +199,24 @@ public final class ClassAccessFlagTest {
public abstract int foo();
}
- @ExpectedClassFlags("[PRIVATE, ABSTRACT]")
+ @ExpectedClassFlags({PRIVATE, ABSTRACT})
private abstract class Foo {}
- @ExpectedClassFlags("[STATIC, INTERFACE, ABSTRACT]")
+ @ExpectedClassFlags({STATIC, INTERFACE, ABSTRACT})
interface StaticTestInterface {}
}
@Retention(RetentionPolicy.RUNTIME)
-@ExpectedClassFlags("[INTERFACE, ABSTRACT, ANNOTATION]")
+@ExpectedClassFlags({INTERFACE, ABSTRACT, ANNOTATION})
@interface ExpectedClassFlags {
- String value();
+ AccessFlag[] value();
}
-@ExpectedClassFlags("[INTERFACE, ABSTRACT]")
+@ExpectedClassFlags({INTERFACE, ABSTRACT})
interface TestInterface {}
-@ExpectedClassFlags("[FINAL, SUPER, ENUM]")
+@ExpectedClassFlags({FINAL, SUPER, ENUM})
enum TestOuterEnum {
INSTANCE;
}
diff --git a/test/jdk/java/lang/reflect/AccessFlag/FieldAccessFlagTest.java b/test/jdk/java/lang/reflect/AccessFlag/FieldAccessFlagTest.java
index edd35f7b6a3..ab12bc75e16 100644
--- a/test/jdk/java/lang/reflect/AccessFlag/FieldAccessFlagTest.java
+++ b/test/jdk/java/lang/reflect/AccessFlag/FieldAccessFlagTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 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
@@ -29,6 +29,11 @@
import java.lang.annotation.*;
import java.lang.reflect.*;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+import static java.lang.reflect.AccessFlag.*;
/*
* Field modifiers include:
@@ -54,39 +59,41 @@ public class FieldAccessFlagTest {
ExpectedFieldFlags expected =
field.getAnnotation(ExpectedFieldFlags.class);
if (expected != null) {
- String actual = field.accessFlags().toString();
- if (!expected.value().equals(actual)) {
+ Set base = EnumSet.noneOf(AccessFlag.class);
+ Collections.addAll(base, expected.value());
+ Set actual = field.accessFlags();
+ if (!base.equals(actual)) {
throw new RuntimeException("On " + field +
- " expected " + expected.value() +
- " got " + actual);
+ " expected " + base +
+ " got " + actual);
}
}
}
// Fields
- @ExpectedFieldFlags("[PUBLIC, STATIC, FINAL]")
+ @ExpectedFieldFlags({PUBLIC, STATIC, FINAL})
public static final String f1 = "foo";
- @ExpectedFieldFlags("[PRIVATE, VOLATILE, TRANSIENT]")
+ @ExpectedFieldFlags({PRIVATE, VOLATILE, TRANSIENT})
private volatile transient String secret = "xxyzzy";
- @ExpectedFieldFlags("[PROTECTED]")
+ @ExpectedFieldFlags({PROTECTED})
protected String meadow = "";
// Enum constant should have the enum access flag set
static enum MetaSynVar {
- @ExpectedFieldFlags("[PUBLIC, STATIC, FINAL, ENUM]")
+ @ExpectedFieldFlags({PUBLIC, STATIC, FINAL, ENUM})
FOO,
- @ExpectedFieldFlags("[PUBLIC, STATIC, FINAL, ENUM]")
+ @ExpectedFieldFlags({PUBLIC, STATIC, FINAL, ENUM})
BAR;
- @ExpectedFieldFlags("[PRIVATE]") // no "ENUM"
+ @ExpectedFieldFlags({PRIVATE}) // no "ENUM"
private int field = 0;
}
@Retention(RetentionPolicy.RUNTIME)
private @interface ExpectedFieldFlags {
- String value();
+ AccessFlag[] value();
}
}
diff --git a/test/jdk/java/lang/reflect/AccessFlag/MethodAccessFlagTest.java b/test/jdk/java/lang/reflect/AccessFlag/MethodAccessFlagTest.java
index a6f65aa31e6..91296727f96 100644
--- a/test/jdk/java/lang/reflect/AccessFlag/MethodAccessFlagTest.java
+++ b/test/jdk/java/lang/reflect/AccessFlag/MethodAccessFlagTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 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
@@ -34,6 +34,11 @@
import java.lang.annotation.*;
import java.lang.reflect.*;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+import static java.lang.reflect.AccessFlag.*;
/*
* Method modifiers include:
@@ -49,7 +54,7 @@ import java.lang.reflect.*;
* Method parameters can be final, synthetic, and mandated.
*/
public abstract class MethodAccessFlagTest {
- @ExpectedMethodFlags("[PUBLIC, STATIC, VARARGS]")
+ @ExpectedMethodFlags({PUBLIC, STATIC, VARARGS})
public static void main(String... args) {
for (var ctor :
MethodAccessFlagTest.class.getDeclaredConstructors()) {
@@ -136,11 +141,17 @@ public abstract class MethodAccessFlagTest {
}
private static void checkExecutable(Executable method) {
- ExpectedMethodFlags emf =
+ ExpectedMethodFlags expected =
method.getAnnotation(ExpectedMethodFlags.class);
- if (emf != null) {
- String actual = method.accessFlags().toString();
- checkString(method.toString(), emf.value(), actual);
+ if (expected != null) {
+ Set base = EnumSet.noneOf(AccessFlag.class);
+ Collections.addAll(base, expected.value());
+ Set actual = method.accessFlags();
+ if (!base.equals(actual)) {
+ throw new RuntimeException("On " + method +
+ " expected " + base +
+ " got " + actual);
+ }
}
}
@@ -155,33 +166,33 @@ public abstract class MethodAccessFlagTest {
}
// Constructors
- @ExpectedMethodFlags("[PUBLIC]")
+ @ExpectedMethodFlags({PUBLIC})
public MethodAccessFlagTest() {}
- @ExpectedMethodFlags("[PROTECTED]")
+ @ExpectedMethodFlags({PROTECTED})
protected MethodAccessFlagTest(int i) {super();}
- @ExpectedMethodFlags("[PRIVATE]")
+ @ExpectedMethodFlags({PRIVATE})
private MethodAccessFlagTest(String s) {super();}
// Methods
- @ExpectedMethodFlags("[PROTECTED, SYNCHRONIZED]")
+ @ExpectedMethodFlags({PROTECTED, SYNCHRONIZED})
protected synchronized void m0() {}
- @ExpectedMethodFlags("[PRIVATE]")
+ @ExpectedMethodFlags({PRIVATE})
private void m1() {}
- @ExpectedMethodFlags("[ABSTRACT]")
+ @ExpectedMethodFlags({ABSTRACT})
abstract void m2();
- @ExpectedMethodFlags("[PUBLIC, FINAL]")
+ @ExpectedMethodFlags({PUBLIC, FINAL})
public final void m3() {}
- @ExpectedMethodFlags("[NATIVE]")
+ @ExpectedMethodFlags({NATIVE})
native void m4();
@Retention(RetentionPolicy.RUNTIME)
private @interface ExpectedMethodFlags {
- String value();
+ AccessFlag[] value();
}
}
diff --git a/test/jdk/java/lang/reflect/AccessFlag/StrictAccessFlagTest.java b/test/jdk/java/lang/reflect/AccessFlag/StrictAccessFlagTest.java
index 53a133b57b8..1c2d6d01df0 100644
--- a/test/jdk/java/lang/reflect/AccessFlag/StrictAccessFlagTest.java
+++ b/test/jdk/java/lang/reflect/AccessFlag/StrictAccessFlagTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 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
@@ -35,6 +35,11 @@
import java.lang.annotation.*;
import java.lang.reflect.*;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Set;
+
+import static java.lang.reflect.AccessFlag.*;
/*
* Test expected value of ACC_STRICT access flag.
@@ -42,7 +47,7 @@ import java.lang.reflect.*;
// Declaring the class strictfp implicitly sets ACC_STRICT on all its
// methods and constructors.
public strictfp class StrictAccessFlagTest {
- @ExpectedFlags("[PUBLIC, STATIC, VARARGS, STRICT]")
+ @ExpectedFlags({PUBLIC, STATIC, VARARGS, STRICT})
public static void main(String... args) {
for (var ctor :
StrictAccessFlagTest.class.getDeclaredConstructors()) {
@@ -59,21 +64,23 @@ public strictfp class StrictAccessFlagTest {
ExpectedFlags expected =
method.getAnnotation(ExpectedFlags.class);
if (expected != null) {
- String actual = method.accessFlags().toString();
- if (!expected.value().equals(actual)) {
+ Set base = EnumSet.noneOf(AccessFlag.class);
+ Collections.addAll(base, expected.value());
+ Set actual = method.accessFlags();
+ if (!base.equals(actual)) {
throw new RuntimeException("On " + method +
- " expected " + expected.value() +
- " got " + actual);
+ " expected " + base +
+ " got " + actual);
}
}
}
// Constructor
- @ExpectedFlags("[PUBLIC, STRICT]")
+ @ExpectedFlags({PUBLIC, STRICT})
public StrictAccessFlagTest() {}
@Retention(RetentionPolicy.RUNTIME)
private @interface ExpectedFlags {
- String value();
+ AccessFlag[] value();
}
}
diff --git a/test/jdk/java/lang/reflect/AccessFlag/VersionedLocationsTest.java b/test/jdk/java/lang/reflect/AccessFlag/VersionedLocationsTest.java
index 353edb7852a..29130cbec38 100644
--- a/test/jdk/java/lang/reflect/AccessFlag/VersionedLocationsTest.java
+++ b/test/jdk/java/lang/reflect/AccessFlag/VersionedLocationsTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 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
@@ -24,7 +24,8 @@
/*
* @test
* @bug 8289106 8293627
- * @summary Tests of AccessFlag.locations(ClassFileFormatVersion)
+ * @summary Tests of AccessFlag.locations(ClassFileFormatVersion) and
+ * accessors on AccessFlag.Location
*/
import java.lang.reflect.AccessFlag;
@@ -79,6 +80,8 @@ public class VersionedLocationsTest {
testSynthetic();
testStrict();
testLatestMatch();
+ testFlagVersionConsistency();
+ testLocationMaskFlagConsistency();
}
/**
@@ -241,12 +244,13 @@ public class VersionedLocationsTest {
private static void testSynthetic() {
for (var cffv : ClassFileFormatVersion.values()) {
Set expected;
- if (cffv.compareTo(ClassFileFormatVersion.RELEASE_6) <= 0) {
+ if (cffv.compareTo(ClassFileFormatVersion.RELEASE_5) < 0) {
expected = Set.of();
} else {
expected =
switch(cffv) {
- case RELEASE_7 -> Set.of(Location.CLASS, Location.FIELD,
+ case RELEASE_5, RELEASE_6,
+ RELEASE_7 -> Set.of(Location.CLASS, Location.FIELD,
Location.METHOD,
Location.INNER_CLASS);
case RELEASE_8 -> Set.of(Location.CLASS, Location.FIELD,
@@ -285,4 +289,47 @@ public class VersionedLocationsTest {
}
}
+ private static void testFlagVersionConsistency() {
+ for (var flag : AccessFlag.values()) {
+ for (var location : AccessFlag.Location.values()) {
+ if (location.flags().contains(flag) != flag.locations().contains(location)) {
+ throw new RuntimeException(String.format("AccessFlag and Location inconsistency:" +
+ "flag %s and location %s are inconsistent for the latest version"));
+ }
+ }
+ }
+ for (var cffv : ClassFileFormatVersion.values()) {
+ for (var flag : AccessFlag.values()) {
+ for (var location : AccessFlag.Location.values()) {
+ if (location.flags(cffv).contains(flag) != flag.locations(cffv).contains(location)) {
+ throw new RuntimeException(String.format("AccessFlag and Location inconsistency:" +
+ "flag %s and location %s are inconsistent for class file version %s"));
+ }
+ }
+ }
+ }
+ }
+
+ private static void testLocationMaskFlagConsistency() {
+ for (var location : AccessFlag.Location.values()) {
+ if (!flagsAndMaskMatch(location.flags(), location.flagsMask())) {
+ throw new RuntimeException(String.format("Flags and mask mismatch for %s", location));
+ }
+ for (var cffv : ClassFileFormatVersion.values()) {
+ if (!flagsAndMaskMatch(location.flags(cffv), location.flagsMask(cffv))) {
+ throw new RuntimeException(String.format("Flags and mask mismatch for %s in %s", location, cffv));
+ }
+ }
+ }
+ }
+
+ private static boolean flagsAndMaskMatch(Set flags, int mask) {
+ for (var flag : flags) {
+ int bit = flag.mask();
+ if (((mask & bit) == 0))
+ return false;
+ mask &= ~bit;
+ }
+ return mask == 0;
+ }
}
diff --git a/test/jdk/java/util/Collection/MOAT.java b/test/jdk/java/util/Collection/MOAT.java
index 1a4e5503f63..1c997a4b26a 100644
--- a/test/jdk/java/util/Collection/MOAT.java
+++ b/test/jdk/java/util/Collection/MOAT.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 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
@@ -138,6 +138,8 @@ public class MOAT {
// Unmodifiable wrappers
testImmutableSet(unmodifiableSet(new HashSet<>(Arrays.asList(1,2,3))), 99);
+ testImmutableSet(AccessFlag.maskToAccessFlags(0, AccessFlag.Location.CLASS), AccessFlag.ABSTRACT);
+ testImmutableSet(AccessFlag.maskToAccessFlags(Modifier.PUBLIC | Modifier.STATIC | Modifier.SYNCHRONIZED, AccessFlag.Location.METHOD), AccessFlag.ABSTRACT);
testImmutableList(unmodifiableList(Arrays.asList(1,2,3)));
testImmutableMap(unmodifiableMap(Collections.singletonMap(1,2)));
testImmutableSeqColl(unmodifiableSequencedCollection(Arrays.asList(1,2,3)), 99);
@@ -478,6 +480,8 @@ public class MOAT {
() -> c.remove(first),
() -> c.removeAll(singleton(first)),
() -> c.retainAll(emptyList()));
+ } else {
+ testEmptyIterator(c.iterator());
}
testForEachMatch(c);
testSpliteratorMatch(c);