< prev index next > src/java.base/share/classes/java/lang/reflect/AccessFlag.java
Print this page
/*
! * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
/*
! * Copyright (c) 2021, 2026, 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
* questions.
*/
package java.lang.reflect;
import java.lang.classfile.ClassModel;
import java.lang.classfile.FieldModel;
import java.lang.classfile.MethodModel;
import java.lang.classfile.attribute.InnerClassInfo;
import java.lang.classfile.attribute.MethodParameterInfo;
import java.lang.classfile.attribute.ModuleAttribute;
import java.lang.classfile.attribute.ModuleExportInfo;
import java.lang.classfile.attribute.ModuleOpenInfo;
import java.lang.classfile.attribute.ModuleRequireInfo;
import java.lang.module.ModuleDescriptor;
- import java.util.AbstractSet;
- import java.util.Collection;
- import java.util.Iterator;
import java.util.List;
import java.util.Map;
- import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
- import java.util.function.Consumer;
- import java.util.function.Predicate;
-
- import jdk.internal.vm.annotation.Stable;
import static java.lang.classfile.ClassFile.*;
import static java.lang.reflect.ClassFileFormatVersion.*;
/**
* questions.
*/
package java.lang.reflect;
+ import jdk.internal.javac.PreviewFeature;
+ import jdk.internal.reflect.AccessFlagSet;
+
+ import java.lang.classfile.ClassFile;
import java.lang.classfile.ClassModel;
import java.lang.classfile.FieldModel;
import java.lang.classfile.MethodModel;
import java.lang.classfile.attribute.InnerClassInfo;
import java.lang.classfile.attribute.MethodParameterInfo;
import java.lang.classfile.attribute.ModuleAttribute;
import java.lang.classfile.attribute.ModuleExportInfo;
import java.lang.classfile.attribute.ModuleOpenInfo;
import java.lang.classfile.attribute.ModuleRequireInfo;
import java.lang.module.ModuleDescriptor;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import static java.lang.classfile.ClassFile.*;
import static java.lang.reflect.ClassFileFormatVersion.*;
/**
* 0x0020}.
*
* @apiNote
* In Java SE 8 and above, the JVM treats the {@code ACC_SUPER}
* flag as set in every class file (JVMS {@jvms 4.1}).
*/
! SUPER(0x0000_0020, false, Location.SET_CLASS, List.of()),
/**
* The module flag {@code ACC_OPEN} with a mask value of {@code
* 0x0020}.
* @see java.lang.module.ModuleDescriptor#isOpen
* 0x0020}.
*
* @apiNote
* In Java SE 8 and above, the JVM treats the {@code ACC_SUPER}
* flag as set in every class file (JVMS {@jvms 4.1}).
+ * If preview feature is enabled,
+ * the {@code 0x0020} access flag bit is {@linkplain #IDENTITY IDENTITY access flag}.
+ */
+ SUPER(0x0000_0020, false,
+ Location.SET_CLASS,
+ List.of()),
+
+ /**
+ * The access flag {@code ACC_IDENTITY} with a mask value of
+ * <code>{@value "0x%04x" ClassFile#ACC_IDENTITY}</code>.
+ *
+ * @jvms value-objects-4.1 Class access and property modifiers
+ * @since Valhalla
*/
! @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS, reflective=true)
+ IDENTITY(ACC_IDENTITY, false,
+ Location.EMPTY_SET,
+ List.of()),
/**
* The module flag {@code ACC_OPEN} with a mask value of {@code
* 0x0020}.
* @see java.lang.module.ModuleDescriptor#isOpen
*/
STRICT(Modifier.STRICT, true, Location.EMPTY_SET,
List.of(Map.entry(RELEASE_16, Location.SET_METHOD),
Map.entry(RELEASE_1, Location.EMPTY_SET))),
+ /**
+ * The access flag {@code ACC_STRICT_INIT}, with a mask value of
+ * <code>{@value "0x%04x" ClassFile#ACC_STRICT_INIT}</code>.
+ *
+ * @jvms strict-fields-4.5 Field access and property flags
+ * @since Valhalla
+ */
+ @PreviewFeature(feature = PreviewFeature.Feature.STRICT_FIELDS, reflective=true)
+ STRICT_INIT(ACC_STRICT_INIT, false,
+ Location.EMPTY_SET,
+ List.of()),
+
/**
* The access flag {@code ACC_SYNTHETIC} with a mask value of
* <code>{@value "0x%04x" Modifier#SYNTHETIC}</code>.
* @see Class#isSynthetic()
* @see Executable#isSynthetic()
* <p>
* This method returns an empty set if this flag is not defined in
* the current class file format version.
*/
public Set<Location> locations() {
! return locations;
}
/**
* {@return locations this flag can be applied to in the given class file
* format version}
* <p>
* This method returns an empty set if this flag is not defined in
* the current class file format version.
*/
public Set<Location> locations() {
! return locations(latest());
}
/**
* {@return locations this flag can be applied to in the given class file
* format version}
* @throws IllegalArgumentException if the mask contains bit
* positions not defined for the location in the current class file format
* @throws NullPointerException if {@code location} is {@code null}
*/
public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) {
! var definition = findDefinition(location); // null checks location
- int unmatchedMask = mask & (~location.flagsMask());
- if (unmatchedMask != 0) {
- throw new IllegalArgumentException("Unmatched bit position 0x" +
- Integer.toHexString(unmatchedMask) +
- " for location " + location);
- }
- return new AccessFlagSet(definition, mask);
}
/**
* {@return an unmodifiable set of access flags for the given mask value
* appropriate for the location in the given class file format version}
* @throws IllegalArgumentException if the mask contains bit
* positions not defined for the location in the current class file format
* @throws NullPointerException if {@code location} is {@code null}
*/
public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) {
! return maskToAccessFlags(mask, location, latest());
}
/**
* {@return an unmodifiable set of access flags for the given mask value
* appropriate for the location in the given class file format version}
* positions not defined for the location in the given class file format
* @throws NullPointerException if {@code location} or {@code cffv} is {@code null}
* @since 25
*/
public static Set<AccessFlag> maskToAccessFlags(int mask, Location location, ClassFileFormatVersion cffv) {
! var definition = findDefinition(location); // null checks location
! int unmatchedMask = mask & (~location.flagsMask(cffv)); // null checks cffv
if (unmatchedMask != 0) {
throw new IllegalArgumentException("Unmatched bit position 0x" +
Integer.toHexString(unmatchedMask) +
" for location " + location +
" for class file format " + cffv);
}
! return new AccessFlagSet(definition, mask);
}
/**
* A location within a {@code class} file where flags can be applied.
* <p>
* positions not defined for the location in the given class file format
* @throws NullPointerException if {@code location} or {@code cffv} is {@code null}
* @since 25
*/
public static Set<AccessFlag> maskToAccessFlags(int mask, Location location, ClassFileFormatVersion cffv) {
! var definition = AccessFlagSet.findDefinition(location, cffv); // null checks location
! int unmatchedMask = mask & (~location.flagsMask(cffv));
if (unmatchedMask != 0) {
throw new IllegalArgumentException("Unmatched bit position 0x" +
Integer.toHexString(unmatchedMask) +
" for location " + location +
" for class file format " + cffv);
}
! return AccessFlagSet.ofValidated(definition, mask);
}
/**
* A location within a {@code class} file where flags can be applied.
* <p>
*/
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.
*
*/
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.
*
// 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 <T> List<Map.Entry<ClassFileFormatVersion, T>> ensureHistoryOrdered(
List<Map.Entry<ClassFileFormatVersion, T>> 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");
}
// 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 <T> List<Map.Entry<ClassFileFormatVersion, T>> ensureHistoryOrdered(
List<Map.Entry<ClassFileFormatVersion, T>> history) {
! ClassFileFormatVersion lastVersion = latest();
for (var e : history) {
var historyVersion = e.getKey();
if (lastVersion.compareTo(historyVersion) <= 0) {
throw new IllegalArgumentException("Versions out of order");
}
* 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}
* the current class file format version.
*
* @since 25
*/
public int flagsMask() {
! return flagsMask(latest());
}
/**
* {@return the union of masks of all access flags defined for
* this location in the given class file format version}
* in the current class file format version.
*
* @since 25
*/
public Set<AccessFlag> 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.
* in the current class file format version.
*
* @since 25
*/
public Set<AccessFlag> flags() {
! return flags(latest());
}
/**
* {@return the set of access flags defined for this location in the
* given class file format version} The set is immutable.
* @param cffv the class file format version
* @throws NullPointerException if {@code cffv} is {@code null}
* @since 25
*/
public Set<AccessFlag> flags(ClassFileFormatVersion cffv) {
! // implicit null check cffv
! return new AccessFlagSet(findDefinition(this), flagsMask(cffv));
- }
- }
-
- 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<AccessFlag> {
- 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<AccessFlag> 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<AccessFlag> {
- 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;
}
}
}
* @param cffv the class file format version
* @throws NullPointerException if {@code cffv} is {@code null}
* @since 25
*/
public Set<AccessFlag> flags(ClassFileFormatVersion cffv) {
! // flagsMask null checks cffv and always returns valid mask
! return AccessFlagSet.ofValidated(AccessFlagSet.findDefinition(this, cffv), flagsMask(cffv));
}
}
}
< prev index next >