< prev index next >

src/java.base/share/classes/java/lang/reflect/AccessFlag.java

Print this page
*** 1,7 ***
  /*
!  * 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
--- 1,7 ---
  /*
!  * 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

*** 23,32 ***
   * 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.*;
  
  /**
--- 23,28 ---
   * 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.*;
  
  /**

*** 160,12 ***
       * 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
--- 156,28 ---
       * 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

*** 262,10 ***
--- 274,22 ---
       */
      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()

*** 351,11 ***
       * <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}
--- 375,11 ---
       * <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}

*** 379,18 ***
       * @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}
--- 403,11 ---
       * @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}

*** 402,19 ***
       * 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>
--- 419,19 ---
       * 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>

*** 499,13 ***
           */
          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.
           *
--- 516,13 ---
           */
          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.
           *

*** 618,11 ***
  
          // 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");
                  }
--- 635,11 ---
  
          // 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");
                  }

*** 652,11 ***
           * 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}
--- 669,11 ---
           * 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}

*** 680,11 ***
           * 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.
--- 697,11 ---
           * 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.

*** 695,138 ***
           * @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;
          }
      }
  }
--- 712,10 ---
           * @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 >