< prev index next >

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

Print this page

  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package java.lang.reflect;
 27 




 28 import java.lang.classfile.ClassModel;
 29 import java.lang.classfile.FieldModel;
 30 import java.lang.classfile.MethodModel;
 31 import java.lang.classfile.attribute.InnerClassInfo;
 32 import java.lang.classfile.attribute.MethodParameterInfo;
 33 import java.lang.classfile.attribute.ModuleAttribute;
 34 import java.lang.classfile.attribute.ModuleExportInfo;
 35 import java.lang.classfile.attribute.ModuleOpenInfo;
 36 import java.lang.classfile.attribute.ModuleRequireInfo;
 37 import java.lang.module.ModuleDescriptor;
 38 import java.util.AbstractSet;
 39 import java.util.Collection;
 40 import java.util.Iterator;
 41 import java.util.List;
 42 import java.util.Map;
 43 import java.util.NoSuchElementException;
 44 import java.util.Objects;
 45 import java.util.Set;
 46 import java.util.function.Consumer;
 47 import java.util.function.Predicate;
 48 
 49 import jdk.internal.vm.annotation.Stable;
 50 
 51 import static java.lang.classfile.ClassFile.*;
 52 import static java.lang.reflect.ClassFileFormatVersion.*;
 53 
 54 /**
 55  * Represents a JVM access or module-related flag on a runtime member,
 56  * such as a {@linkplain Class class}, {@linkplain Field field}, or
 57  * {@linkplain Executable method}.
 58  *
 59  * <P>JVM access and module-related flags are related to, but distinct
 60  * from Java language {@linkplain Modifier modifiers}. Some modifiers
 61  * and access flags have a one-to-one correspondence, such as {@code
 62  * public}. In other cases, some language-level modifiers do
 63  * <em>not</em> have an access flag, such as {@code sealed} (JVMS
 64  * {@jvms 4.7.31}) and some access flags have no corresponding
 65  * modifier, such as {@linkplain #SYNTHETIC synthetic}.
 66  *
 67  * <p>The values for the constants representing the access and module
 68  * flags are taken from sections of <cite>The Java Virtual Machine
 69  * Specification</cite> including {@jvms 4.1} (class access and

145     STATIC(Modifier.STATIC, true, Location.SET_FIELD_METHOD_INNER_CLASS,
146            List.of(Map.entry(RELEASE_0, Location.SET_FIELD_METHOD))),
147 
148     /**
149      * The access flag {@code ACC_FINAL}, corresponding to the source
150      * modifier {@link Modifier#FINAL final}, with a mask
151      * value of <code>{@value "0x%04x" Modifier#FINAL}</code>.
152      */
153     FINAL(Modifier.FINAL, true,
154           Location.SET_FINAL_8,
155           List.of(Map.entry(RELEASE_7, Location.SET_CLASS_FIELD_METHOD_INNER_CLASS),
156                   Map.entry(RELEASE_0, Location.SET_CLASS_FIELD_METHOD))),
157 
158     /**
159      * The access flag {@code ACC_SUPER} with a mask value of {@code
160      * 0x0020}.
161      *
162      * @apiNote
163      * In Java SE 8 and above, the JVM treats the {@code ACC_SUPER}
164      * flag as set in every class file (JVMS {@jvms 4.1}).



















165      */
166     SUPER(0x0000_0020, false, Location.SET_CLASS, List.of()),



167 
168     /**
169      * The module flag {@code ACC_OPEN} with a mask value of {@code
170      * 0x0020}.
171      * @see java.lang.module.ModuleDescriptor#isOpen
172      */
173     OPEN(0x0000_0020, false, Location.SET_MODULE,
174          List.of(Map.entry(RELEASE_8, Location.EMPTY_SET))),
175 
176     /**
177      * The module requires flag {@code ACC_TRANSITIVE} with a mask
178      * value of {@code 0x0020}.
179      * @see java.lang.module.ModuleDescriptor.Requires.Modifier#TRANSITIVE
180      */
181     TRANSITIVE(0x0000_0020, false, Location.SET_MODULE_REQUIRES,
182                List.of(Map.entry(RELEASE_8, Location.EMPTY_SET))),
183 
184     /**
185      * The access flag {@code ACC_SYNCHRONIZED}, corresponding to the
186      * source modifier {@link Modifier#SYNCHRONIZED synchronized}, with

247      * value of <code>{@value "0x%04x" Modifier#ABSTRACT}</code>.
248      */
249     ABSTRACT(Modifier.ABSTRACT, true,
250              Location.SET_CLASS_METHOD_INNER_CLASS,
251              List.of(Map.entry(RELEASE_0, Location.SET_CLASS_METHOD))),
252 
253     /**
254      * The access flag {@code ACC_STRICT}, corresponding to the source
255      * modifier {@link Modifier#STRICT strictfp}, with a mask value of
256      * <code>{@value "0x%04x" Modifier#STRICT}</code>.
257      *
258      * @apiNote
259      * The {@code ACC_STRICT} access flag is defined for class file
260      * major versions 46 through 60, inclusive (JVMS {@jvms 4.6}),
261      * corresponding to Java SE 1.2 through 16.
262      */
263     STRICT(Modifier.STRICT, true, Location.EMPTY_SET,
264            List.of(Map.entry(RELEASE_16, Location.SET_METHOD),
265                    Map.entry(RELEASE_1, Location.EMPTY_SET))),
266 
















267     /**
268      * The access flag {@code ACC_SYNTHETIC} with a mask value of
269      * <code>{@value "0x%04x" Modifier#SYNTHETIC}</code>.
270      * @see Class#isSynthetic()
271      * @see Executable#isSynthetic()
272      * @see java.lang.module.ModuleDescriptor.Modifier#SYNTHETIC
273      */
274     SYNTHETIC(Modifier.SYNTHETIC, false, Location.SET_SYNTHETIC_9,
275               List.of(Map.entry(RELEASE_8, Location.SET_SYNTHETIC_8),
276                       Map.entry(RELEASE_7, Location.SET_SYNTHETIC_5),
277                       Map.entry(RELEASE_4, Location.EMPTY_SET))),
278 
279     /**
280      * The access flag {@code ACC_ANNOTATION} with a mask value of
281      * <code>{@value "0x%04x" Modifier#ANNOTATION}</code>.
282      * @see Class#isAnnotation()
283      */
284     ANNOTATION(Modifier.ANNOTATION, false, Location.SET_CLASS_INNER_CLASS,
285                List.of(Map.entry(RELEASE_4, Location.EMPTY_SET))),
286 

336     public int mask() {
337         return mask;
338     }
339 
340     /**
341      * {@return whether or not this flag has a directly corresponding
342      * modifier in the Java programming language}
343      */
344     public boolean sourceModifier() {
345         return sourceModifier;
346     }
347 
348     /**
349      * {@return locations this flag can be applied to in the current class file
350      * format version}
351      * <p>
352      * This method returns an empty set if this flag is not defined in
353      * the current class file format version.
354      */
355     public Set<Location> locations() {
356         return locations;
357     }
358 
359     /**
360      * {@return locations this flag can be applied to in the given class file
361      * format version}
362      * <p>
363      * This method returns an empty set if this flag is not defined in
364      * the given {@code cffv}.
365      *
366      * @param cffv the class file format version to use
367      * @throws NullPointerException if the parameter is {@code null}
368      */
369     public Set<Location> locations(ClassFileFormatVersion cffv) {
370         return Location.findInHistory(locations, historicalLocations, cffv);
371     }
372 
373     /**
374      * {@return an unmodifiable set of access flags for the given mask value
375      * appropriate for the location in the current class file format version}
376      *
377      * @param mask bit mask of access flags
378      * @param location context to interpret mask value
379      * @throws IllegalArgumentException if the mask contains bit
380      * positions not defined for the location in the current class file format
381      * @throws NullPointerException if {@code location} is {@code null}
382      */
383     public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) {
384         var definition = findDefinition(location);  // null checks location
385         int unmatchedMask = mask & (~location.flagsMask());
386         if (unmatchedMask != 0) {
387             throw new IllegalArgumentException("Unmatched bit position 0x" +
388                     Integer.toHexString(unmatchedMask) +
389                     " for location " + location);
390         }
391         return new AccessFlagSet(definition, mask);
392     }
393 
394     /**
395      * {@return an unmodifiable set of access flags for the given mask value
396      * appropriate for the location in the given class file format version}
397      *
398      * @param mask bit mask of access flags
399      * @param location context to interpret mask value
400      * @param cffv the class file format to interpret mask value
401      * @throws IllegalArgumentException if the mask contains bit
402      * positions not defined for the location in the given class file format
403      * @throws NullPointerException if {@code location} or {@code cffv} is {@code null}
404      * @since 25
405      */
406     public static Set<AccessFlag> maskToAccessFlags(int mask, Location location, ClassFileFormatVersion cffv) {
407         var definition = findDefinition(location);  // null checks location
408         int unmatchedMask = mask & (~location.flagsMask(cffv));  // null checks cffv
409         if (unmatchedMask != 0) {
410             throw new IllegalArgumentException("Unmatched bit position 0x" +
411                     Integer.toHexString(unmatchedMask) +
412                     " for location " + location +
413                     " for class file format " + cffv);
414         }
415         return new AccessFlagSet(definition, mask);
416     }
417 
418     /**
419      * A location within a {@code class} file where flags can be applied.
420      * <p>
421      * Note that since these locations represent {@code class} file structures
422      * rather than language structures, many language structures, such
423      * as constructors and interfaces, are <em>not</em> present.
424      * @since 20
425      */
426     public enum Location {
427         /**
428          * Class location.
429          *
430          * @see Class#accessFlags()
431          * @see ClassModel#flags()
432          * @jvms 4.1 The {@code ClassFile} Structure
433          */
434         CLASS(ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
435               ACC_INTERFACE | ACC_ABSTRACT |

477                        Map.entry(RELEASE_4, // no bridge, varargs, synthetic
478                                  ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
479                                  ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
480                                  ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT),
481                        Map.entry(RELEASE_1, // no strict
482                                  ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
483                                  ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
484                                  ACC_NATIVE | ACC_ABSTRACT))),
485 
486         /**
487          * Inner class location.
488          *
489          * @see Class#accessFlags()
490          * @see InnerClassInfo#flags()
491          * @jvms 4.7.6 The {@code InnerClasses} Attribute
492          */
493         INNER_CLASS(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
494                     ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT |
495                     ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM,
496                     List.of(Map.entry(RELEASE_4, // no synthetic, annotation, enum
497                             ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
498                             ACC_STATIC | ACC_FINAL | ACC_INTERFACE |
499                             ACC_ABSTRACT),
500                             Map.entry(RELEASE_0, 0))), // did not exist
501 
502         /**
503          * Method parameter location.
504          *
505          * @see Parameter#accessFlags()
506          * @see MethodParameterInfo#flags()
507          * @jvms 4.7.24 The {@code MethodParameters} Attribute
508          */
509         METHOD_PARAMETER(ACC_FINAL | ACC_SYNTHETIC | ACC_MANDATED,
510                          List.of(Map.entry(RELEASE_7, 0))),  // did not exist
511 
512         /**
513          * Module location.
514          *
515          * @see ModuleDescriptor#accessFlags()
516          * @see ModuleAttribute#moduleFlags()
517          * @jvms 4.7.25 The {@code Module} Attribute
518          */
519         MODULE(ACC_OPEN | ACC_SYNTHETIC | ACC_MANDATED,

595                      MODULE_EXPORTS, MODULE_OPENS);
596         private static final Set<Location> SET_MANDATED_9 =
597             Set.of(METHOD_PARAMETER, // From 8
598                    // Starting in 9
599                    MODULE, MODULE_REQUIRES,
600                    MODULE_EXPORTS, MODULE_OPENS);
601 
602         private final int flagsMask;
603         private final List<Map.Entry<ClassFileFormatVersion, Integer>> historicalFlagsMasks;
604 
605         Location(int flagsMask,
606                  List<Map.Entry<ClassFileFormatVersion, Integer>> historicalFlagsMasks) {
607             this.flagsMask = flagsMask;
608             this.historicalFlagsMasks = ensureHistoryOrdered(historicalFlagsMasks);
609         }
610 
611         // Ensures the historical versions are from newest to oldest and do not include the latest
612         // These 2 utilities reside in Location because Location must be initialized before AccessFlag
613         private static <T> List<Map.Entry<ClassFileFormatVersion, T>> ensureHistoryOrdered(
614                 List<Map.Entry<ClassFileFormatVersion, T>> history) {
615             ClassFileFormatVersion lastVersion = ClassFileFormatVersion.latest();
616             for (var e : history) {
617                 var historyVersion = e.getKey();
618                 if (lastVersion.compareTo(historyVersion) <= 0) {
619                     throw new IllegalArgumentException("Versions out of order");
620                 }
621                 lastVersion = historyVersion;
622             }
623             return history;
624         }
625 
626         private static <T> T findInHistory(T candidate, List<Map.Entry<ClassFileFormatVersion, T>> history,
627                                            ClassFileFormatVersion cffv) {
628             Objects.requireNonNull(cffv);
629             for (var e : history) {
630                 if (e.getKey().compareTo(cffv) < 0) {
631                     // last version found was valid
632                     return candidate;
633                 }
634                 candidate = e.getValue();
635             }
636             return candidate;
637         }
638 
639         /**
640          * {@return the union of masks of all access flags defined for
641          * this location in the current class file format version}
642          * <p>
643          * This method returns {@code 0} if this location does not exist in
644          * the current class file format version.
645          *
646          * @since 25
647          */
648         public int flagsMask() {
649             return flagsMask;
650         }
651 
652         /**
653          * {@return the union of masks of all access flags defined for
654          * this location in the given class file format version}
655          * <p>
656          * This method returns {@code 0} if this location does not exist in
657          * the given {@code cffv}.
658          *
659          * @param cffv the class file format version
660          * @throws NullPointerException if {@code cffv} is {@code null}
661          * @since 25
662          */
663         public int flagsMask(ClassFileFormatVersion cffv) {
664             return findInHistory(flagsMask, historicalFlagsMasks, cffv);
665         }
666 
667         /**
668          * {@return the set of access flags defined for this location in the
669          * current class file format version}  The set is immutable.
670          * <p>
671          * This method returns an empty set if this location does not exist
672          * in the current class file format version.
673          *
674          * @since 25
675          */
676         public Set<AccessFlag> flags() {
677             return new AccessFlagSet(findDefinition(this), flagsMask());
678         }
679 
680         /**
681          * {@return the set of access flags defined for this location in the
682          * given class file format version}  The set is immutable.
683          * <p>
684          * This method returns an empty set if this location does not exist
685          * in the given {@code cffv}.
686          *
687          * @param cffv the class file format version
688          * @throws NullPointerException if {@code cffv} is {@code null}
689          * @since 25
690          */
691         public Set<AccessFlag> flags(ClassFileFormatVersion cffv) {
692             // implicit null check cffv
693             return new AccessFlagSet(findDefinition(this), flagsMask(cffv));
694         }
695     }
696 
697     private static AccessFlag[] createDefinition(AccessFlag... known) {
698         var ret = new AccessFlag[Character.SIZE];
699         for (var flag : known) {
700             var mask = flag.mask;
701             int pos = Integer.numberOfTrailingZeros(mask);
702             assert ret[pos] == null : ret[pos] + " " + flag;
703             ret[pos] = flag;
704         }
705         return ret;
706     }
707 
708     // Will take extra args in the future for valhalla switch
709     private static AccessFlag[] findDefinition(Location location) {
710         return switch (location) {
711             case CLASS -> CLASS_FLAGS;
712             case FIELD -> FIELD_FLAGS;
713             case METHOD -> METHOD_FLAGS;
714             case INNER_CLASS -> INNER_CLASS_FLAGS;
715             case METHOD_PARAMETER -> METHOD_PARAMETER_FLAGS;
716             case MODULE -> MODULE_FLAGS;
717             case MODULE_REQUIRES -> MODULE_REQUIRES_FLAGS;
718             case MODULE_EXPORTS -> MODULE_EXPORTS_FLAGS;
719             case MODULE_OPENS -> MODULE_OPENS_FLAGS;
720         };
721     }
722 
723     private static final @Stable AccessFlag[] // Can use stable array and lazy init in the future
724             CLASS_FLAGS = createDefinition(PUBLIC, FINAL, SUPER, INTERFACE, ABSTRACT, SYNTHETIC, ANNOTATION, ENUM, MODULE),
725             FIELD_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, VOLATILE, TRANSIENT, SYNTHETIC, ENUM),
726             METHOD_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, SYNCHRONIZED, BRIDGE, VARARGS, NATIVE, ABSTRACT, STRICT, SYNTHETIC),
727             INNER_CLASS_FLAGS = createDefinition(PUBLIC, PRIVATE, PROTECTED, STATIC, FINAL, INTERFACE, ABSTRACT, SYNTHETIC, ANNOTATION, ENUM),
728             METHOD_PARAMETER_FLAGS = createDefinition(FINAL, SYNTHETIC, MANDATED),
729             MODULE_FLAGS = createDefinition(OPEN, SYNTHETIC, MANDATED),
730             MODULE_REQUIRES_FLAGS = createDefinition(TRANSITIVE, STATIC_PHASE, SYNTHETIC, MANDATED),
731             MODULE_EXPORTS_FLAGS = createDefinition(SYNTHETIC, MANDATED),
732             MODULE_OPENS_FLAGS = createDefinition(SYNTHETIC, MANDATED);
733 
734     private static int undefinedMask(AccessFlag[] definition, int mask) {
735         assert definition.length == Character.SIZE;
736         int definedMask = 0;
737         for (int i = 0; i < Character.SIZE; i++) {
738             if (definition[i] != null) {
739                 definedMask |= 1 << i;
740             }
741         }
742         return mask & ~definedMask;
743     }
744 
745     private static final class AccessFlagSet extends AbstractSet<AccessFlag> {
746         private final @Stable AccessFlag[] definition;
747         private final int mask;
748 
749         // all mutating methods throw UnsupportedOperationException
750         @Override public boolean add(AccessFlag e) { throw uoe(); }
751         @Override public boolean addAll(Collection<? extends AccessFlag> c) { throw uoe(); }
752         @Override public void    clear() { throw uoe(); }
753         @Override public boolean remove(Object o) { throw uoe(); }
754         @Override public boolean removeAll(Collection<?> c) { throw uoe(); }
755         @Override public boolean removeIf(Predicate<? super AccessFlag> filter) { throw uoe(); }
756         @Override public boolean retainAll(Collection<?> c) { throw uoe(); }
757         private static UnsupportedOperationException uoe() { return new UnsupportedOperationException(); }
758 
759         private AccessFlagSet(AccessFlag[] definition, int mask) {
760             assert undefinedMask(definition, mask) == 0 : mask;
761             this.definition = definition;
762             this.mask = mask;
763         }
764 
765         @Override
766         public Iterator<AccessFlag> iterator() {
767             return new AccessFlagIterator(definition, mask);
768         }
769 
770         @Override
771         public void forEach(Consumer<? super AccessFlag> action) {
772             Objects.requireNonNull(action); // in case of empty
773             for (int i = 0; i < Character.SIZE; i++) {
774                 if ((mask & (1 << i)) != 0) {
775                     action.accept(definition[i]);
776                 }
777             }
778         }
779 
780         private static final class AccessFlagIterator implements Iterator<AccessFlag> {
781             private final @Stable AccessFlag[] definition;
782             private int remainingMask;
783 
784             private AccessFlagIterator(AccessFlag[] definition, int remainingMask) {
785                 this.definition = definition;
786                 this.remainingMask = remainingMask;
787             }
788 
789             @Override
790             public boolean hasNext() {
791                 return remainingMask != 0;
792             }
793 
794             @Override
795             public AccessFlag next() {
796                 int flagBit = Integer.lowestOneBit(remainingMask);
797                 if (flagBit == 0) {
798                     throw new NoSuchElementException();
799                 }
800                 remainingMask &= ~flagBit;
801                 return definition[Integer.numberOfTrailingZeros(flagBit)];
802             }
803         }
804 
805         @Override
806         public int size() {
807             return Integer.bitCount(mask);
808         }
809 
810         @Override
811         public boolean contains(Object o) {
812             if (Objects.requireNonNull(o) instanceof AccessFlag flag) {
813                 int bit = flag.mask;
814                 return (bit & mask) != 0 && definition[Integer.numberOfTrailingZeros(bit)] == flag;
815             }
816             return false;
817         }
818 
819         @Override
820         public boolean isEmpty() {
821             return mask == 0;
822         }
823     }
824 }

  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package java.lang.reflect;
 27 
 28 import jdk.internal.javac.PreviewFeature;
 29 import jdk.internal.reflect.AccessFlagSet;
 30 
 31 import java.lang.classfile.ClassFile;
 32 import java.lang.classfile.ClassModel;
 33 import java.lang.classfile.FieldModel;
 34 import java.lang.classfile.MethodModel;
 35 import java.lang.classfile.attribute.InnerClassInfo;
 36 import java.lang.classfile.attribute.MethodParameterInfo;
 37 import java.lang.classfile.attribute.ModuleAttribute;
 38 import java.lang.classfile.attribute.ModuleExportInfo;
 39 import java.lang.classfile.attribute.ModuleOpenInfo;
 40 import java.lang.classfile.attribute.ModuleRequireInfo;
 41 import java.lang.module.ModuleDescriptor;



 42 import java.util.List;
 43 import java.util.Map;

 44 import java.util.Objects;
 45 import java.util.Set;




 46 
 47 import static java.lang.classfile.ClassFile.*;
 48 import static java.lang.reflect.ClassFileFormatVersion.*;
 49 
 50 /**
 51  * Represents a JVM access or module-related flag on a runtime member,
 52  * such as a {@linkplain Class class}, {@linkplain Field field}, or
 53  * {@linkplain Executable method}.
 54  *
 55  * <P>JVM access and module-related flags are related to, but distinct
 56  * from Java language {@linkplain Modifier modifiers}. Some modifiers
 57  * and access flags have a one-to-one correspondence, such as {@code
 58  * public}. In other cases, some language-level modifiers do
 59  * <em>not</em> have an access flag, such as {@code sealed} (JVMS
 60  * {@jvms 4.7.31}) and some access flags have no corresponding
 61  * modifier, such as {@linkplain #SYNTHETIC synthetic}.
 62  *
 63  * <p>The values for the constants representing the access and module
 64  * flags are taken from sections of <cite>The Java Virtual Machine
 65  * Specification</cite> including {@jvms 4.1} (class access and

141     STATIC(Modifier.STATIC, true, Location.SET_FIELD_METHOD_INNER_CLASS,
142            List.of(Map.entry(RELEASE_0, Location.SET_FIELD_METHOD))),
143 
144     /**
145      * The access flag {@code ACC_FINAL}, corresponding to the source
146      * modifier {@link Modifier#FINAL final}, with a mask
147      * value of <code>{@value "0x%04x" Modifier#FINAL}</code>.
148      */
149     FINAL(Modifier.FINAL, true,
150           Location.SET_FINAL_8,
151           List.of(Map.entry(RELEASE_7, Location.SET_CLASS_FIELD_METHOD_INNER_CLASS),
152                   Map.entry(RELEASE_0, Location.SET_CLASS_FIELD_METHOD))),
153 
154     /**
155      * The access flag {@code ACC_SUPER} with a mask value of {@code
156      * 0x0020}.
157      *
158      * @apiNote
159      * In Java SE 8 and above, the JVM treats the {@code ACC_SUPER}
160      * flag as set in every class file (JVMS {@jvms 4.1}).
161      * If preview feature is enabled,
162      * the {@code 0x0020} access flag bit is {@linkplain #IDENTITY IDENTITY access flag}.
163      */
164     SUPER(0x0000_0020, false,
165           Location.SET_CLASS,
166           List.of()),
167 
168     /**
169      * The access flag {@code ACC_IDENTITY} with a mask value of
170      * <code>{@value "0x%04x" ClassFile#ACC_IDENTITY}</code>.
171      * <p>
172      * If a class does not use preview features, the {@code ACC_IDENTITY} flag
173      * is considered always set for that class; if an interface or module
174      * descriptor does not use preview features, the {@code ACC_IDENTITY} flag
175      * is considered not set for that interface or module descriptor.
176      *
177      * @see Class#isValue()
178      * @jvms value-objects-4.1 Class access and property modifiers
179      * @since 28
180      */
181     @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS, reflective=true)
182     IDENTITY(ACC_IDENTITY, false,
183              Location.EMPTY_SET,
184              List.of()),
185 
186     /**
187      * The module flag {@code ACC_OPEN} with a mask value of {@code
188      * 0x0020}.
189      * @see java.lang.module.ModuleDescriptor#isOpen
190      */
191     OPEN(0x0000_0020, false, Location.SET_MODULE,
192          List.of(Map.entry(RELEASE_8, Location.EMPTY_SET))),
193 
194     /**
195      * The module requires flag {@code ACC_TRANSITIVE} with a mask
196      * value of {@code 0x0020}.
197      * @see java.lang.module.ModuleDescriptor.Requires.Modifier#TRANSITIVE
198      */
199     TRANSITIVE(0x0000_0020, false, Location.SET_MODULE_REQUIRES,
200                List.of(Map.entry(RELEASE_8, Location.EMPTY_SET))),
201 
202     /**
203      * The access flag {@code ACC_SYNCHRONIZED}, corresponding to the
204      * source modifier {@link Modifier#SYNCHRONIZED synchronized}, with

265      * value of <code>{@value "0x%04x" Modifier#ABSTRACT}</code>.
266      */
267     ABSTRACT(Modifier.ABSTRACT, true,
268              Location.SET_CLASS_METHOD_INNER_CLASS,
269              List.of(Map.entry(RELEASE_0, Location.SET_CLASS_METHOD))),
270 
271     /**
272      * The access flag {@code ACC_STRICT}, corresponding to the source
273      * modifier {@link Modifier#STRICT strictfp}, with a mask value of
274      * <code>{@value "0x%04x" Modifier#STRICT}</code>.
275      *
276      * @apiNote
277      * The {@code ACC_STRICT} access flag is defined for class file
278      * major versions 46 through 60, inclusive (JVMS {@jvms 4.6}),
279      * corresponding to Java SE 1.2 through 16.
280      */
281     STRICT(Modifier.STRICT, true, Location.EMPTY_SET,
282            List.of(Map.entry(RELEASE_16, Location.SET_METHOD),
283                    Map.entry(RELEASE_1, Location.EMPTY_SET))),
284 
285     /**
286      * The access flag {@code ACC_STRICT_INIT}, with a mask value of
287      * <code>{@value "0x%04x" ClassFile#ACC_STRICT_INIT}</code>.
288      *
289      * <p>The {@code ACC_STRICT_INIT} flag is considered not set for a field
290      * declared in a class or interface that does not use preview features.
291      *
292      * @see Field#isStrictInit()
293      * @jvms strict-fields-4.5 Field access and property flags
294      * @since 28
295      */
296     @PreviewFeature(feature = PreviewFeature.Feature.STRICT_FIELDS, reflective=true)
297     STRICT_INIT(ACC_STRICT_INIT, false,
298                 Location.EMPTY_SET,
299                 List.of()),
300 
301     /**
302      * The access flag {@code ACC_SYNTHETIC} with a mask value of
303      * <code>{@value "0x%04x" Modifier#SYNTHETIC}</code>.
304      * @see Class#isSynthetic()
305      * @see Executable#isSynthetic()
306      * @see java.lang.module.ModuleDescriptor.Modifier#SYNTHETIC
307      */
308     SYNTHETIC(Modifier.SYNTHETIC, false, Location.SET_SYNTHETIC_9,
309               List.of(Map.entry(RELEASE_8, Location.SET_SYNTHETIC_8),
310                       Map.entry(RELEASE_7, Location.SET_SYNTHETIC_5),
311                       Map.entry(RELEASE_4, Location.EMPTY_SET))),
312 
313     /**
314      * The access flag {@code ACC_ANNOTATION} with a mask value of
315      * <code>{@value "0x%04x" Modifier#ANNOTATION}</code>.
316      * @see Class#isAnnotation()
317      */
318     ANNOTATION(Modifier.ANNOTATION, false, Location.SET_CLASS_INNER_CLASS,
319                List.of(Map.entry(RELEASE_4, Location.EMPTY_SET))),
320 

370     public int mask() {
371         return mask;
372     }
373 
374     /**
375      * {@return whether or not this flag has a directly corresponding
376      * modifier in the Java programming language}
377      */
378     public boolean sourceModifier() {
379         return sourceModifier;
380     }
381 
382     /**
383      * {@return locations this flag can be applied to in the current class file
384      * format version}
385      * <p>
386      * This method returns an empty set if this flag is not defined in
387      * the current class file format version.
388      */
389     public Set<Location> locations() {
390         return locations(latest());
391     }
392 
393     /**
394      * {@return locations this flag can be applied to in the given class file
395      * format version}
396      * <p>
397      * This method returns an empty set if this flag is not defined in
398      * the given {@code cffv}.
399      *
400      * @param cffv the class file format version to use
401      * @throws NullPointerException if the parameter is {@code null}
402      */
403     public Set<Location> locations(ClassFileFormatVersion cffv) {
404         return Location.findInHistory(locations, historicalLocations, cffv);
405     }
406 
407     /**
408      * {@return an unmodifiable set of access flags for the given mask value
409      * appropriate for the location in the current class file format version}
410      *
411      * @param mask bit mask of access flags
412      * @param location context to interpret mask value
413      * @throws IllegalArgumentException if the mask contains bit
414      * positions not defined for the location in the current class file format
415      * @throws NullPointerException if {@code location} is {@code null}
416      */
417     public static Set<AccessFlag> maskToAccessFlags(int mask, Location location) {
418         return maskToAccessFlags(mask, location, latest());







419     }
420 
421     /**
422      * {@return an unmodifiable set of access flags for the given mask value
423      * appropriate for the location in the given class file format version}
424      *
425      * @param mask bit mask of access flags
426      * @param location context to interpret mask value
427      * @param cffv the class file format to interpret mask value
428      * @throws IllegalArgumentException if the mask contains bit
429      * positions not defined for the location in the given class file format
430      * @throws NullPointerException if {@code location} or {@code cffv} is {@code null}
431      * @since 25
432      */
433     public static Set<AccessFlag> maskToAccessFlags(int mask, Location location, ClassFileFormatVersion cffv) {
434         var definition = AccessFlagSet.findDefinition(location, cffv);  // null checks location
435         int unmatchedMask = mask & (~location.flagsMask(cffv));
436         if (unmatchedMask != 0) {
437             throw new IllegalArgumentException("Unmatched bit position 0x" +
438                     Integer.toHexString(unmatchedMask) +
439                     " for location " + location +
440                     " for class file format " + cffv);
441         }
442         return AccessFlagSet.ofValidated(definition, mask);
443     }
444 
445     /**
446      * A location within a {@code class} file where flags can be applied.
447      * <p>
448      * Note that since these locations represent {@code class} file structures
449      * rather than language structures, many language structures, such
450      * as constructors and interfaces, are <em>not</em> present.
451      * @since 20
452      */
453     public enum Location {
454         /**
455          * Class location.
456          *
457          * @see Class#accessFlags()
458          * @see ClassModel#flags()
459          * @jvms 4.1 The {@code ClassFile} Structure
460          */
461         CLASS(ACC_PUBLIC | ACC_FINAL | ACC_SUPER |
462               ACC_INTERFACE | ACC_ABSTRACT |

504                        Map.entry(RELEASE_4, // no bridge, varargs, synthetic
505                                  ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
506                                  ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
507                                  ACC_NATIVE | ACC_ABSTRACT | ACC_STRICT),
508                        Map.entry(RELEASE_1, // no strict
509                                  ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
510                                  ACC_STATIC | ACC_FINAL | ACC_SYNCHRONIZED |
511                                  ACC_NATIVE | ACC_ABSTRACT))),
512 
513         /**
514          * Inner class location.
515          *
516          * @see Class#accessFlags()
517          * @see InnerClassInfo#flags()
518          * @jvms 4.7.6 The {@code InnerClasses} Attribute
519          */
520         INNER_CLASS(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
521                     ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT |
522                     ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM,
523                     List.of(Map.entry(RELEASE_4, // no synthetic, annotation, enum
524                                       ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED |
525                                       ACC_STATIC | ACC_FINAL | ACC_INTERFACE |
526                                       ACC_ABSTRACT),
527                             Map.entry(RELEASE_0, 0))), // did not exist
528 
529         /**
530          * Method parameter location.
531          *
532          * @see Parameter#accessFlags()
533          * @see MethodParameterInfo#flags()
534          * @jvms 4.7.24 The {@code MethodParameters} Attribute
535          */
536         METHOD_PARAMETER(ACC_FINAL | ACC_SYNTHETIC | ACC_MANDATED,
537                          List.of(Map.entry(RELEASE_7, 0))),  // did not exist
538 
539         /**
540          * Module location.
541          *
542          * @see ModuleDescriptor#accessFlags()
543          * @see ModuleAttribute#moduleFlags()
544          * @jvms 4.7.25 The {@code Module} Attribute
545          */
546         MODULE(ACC_OPEN | ACC_SYNTHETIC | ACC_MANDATED,

622                      MODULE_EXPORTS, MODULE_OPENS);
623         private static final Set<Location> SET_MANDATED_9 =
624             Set.of(METHOD_PARAMETER, // From 8
625                    // Starting in 9
626                    MODULE, MODULE_REQUIRES,
627                    MODULE_EXPORTS, MODULE_OPENS);
628 
629         private final int flagsMask;
630         private final List<Map.Entry<ClassFileFormatVersion, Integer>> historicalFlagsMasks;
631 
632         Location(int flagsMask,
633                  List<Map.Entry<ClassFileFormatVersion, Integer>> historicalFlagsMasks) {
634             this.flagsMask = flagsMask;
635             this.historicalFlagsMasks = ensureHistoryOrdered(historicalFlagsMasks);
636         }
637 
638         // Ensures the historical versions are from newest to oldest and do not include the latest
639         // These 2 utilities reside in Location because Location must be initialized before AccessFlag
640         private static <T> List<Map.Entry<ClassFileFormatVersion, T>> ensureHistoryOrdered(
641                 List<Map.Entry<ClassFileFormatVersion, T>> history) {
642             ClassFileFormatVersion lastVersion = latest();
643             for (var e : history) {
644                 var historyVersion = e.getKey();
645                 if (lastVersion.compareTo(historyVersion) <= 0) {
646                     throw new IllegalArgumentException("Versions out of order");
647                 }
648                 lastVersion = historyVersion;
649             }
650             return history;
651         }
652 
653         private static <T> T findInHistory(T candidate, List<Map.Entry<ClassFileFormatVersion, T>> history,
654                                            ClassFileFormatVersion cffv) {
655             Objects.requireNonNull(cffv);
656             for (var e : history) {
657                 if (e.getKey().compareTo(cffv) < 0) {
658                     // last version found was valid
659                     return candidate;
660                 }
661                 candidate = e.getValue();
662             }
663             return candidate;
664         }
665 
666         /**
667          * {@return the union of masks of all access flags defined for
668          * this location in the current class file format version}
669          * <p>
670          * This method returns {@code 0} if this location does not exist in
671          * the current class file format version.
672          *
673          * @since 25
674          */
675         public int flagsMask() {
676             return flagsMask(latest());
677         }
678 
679         /**
680          * {@return the union of masks of all access flags defined for
681          * this location in the given class file format version}
682          * <p>
683          * This method returns {@code 0} if this location does not exist in
684          * the given {@code cffv}.
685          *
686          * @param cffv the class file format version
687          * @throws NullPointerException if {@code cffv} is {@code null}
688          * @since 25
689          */
690         public int flagsMask(ClassFileFormatVersion cffv) {
691             return findInHistory(flagsMask, historicalFlagsMasks, cffv);
692         }
693 
694         /**
695          * {@return the set of access flags defined for this location in the
696          * current class file format version}  The set is immutable.
697          * <p>
698          * This method returns an empty set if this location does not exist
699          * in the current class file format version.
700          *
701          * @since 25
702          */
703         public Set<AccessFlag> flags() {
704             return flags(latest());
705         }
706 
707         /**
708          * {@return the set of access flags defined for this location in the
709          * given class file format version}  The set is immutable.
710          * <p>
711          * This method returns an empty set if this location does not exist
712          * in the given {@code cffv}.
713          *
714          * @param cffv the class file format version
715          * @throws NullPointerException if {@code cffv} is {@code null}
716          * @since 25
717          */
718         public Set<AccessFlag> flags(ClassFileFormatVersion cffv) {
719             // flagsMask null checks cffv and always returns valid mask
720             return AccessFlagSet.ofValidated(AccessFlagSet.findDefinition(this, cffv), flagsMask(cffv));
































































































































721         }
722     }
723 }
< prev index next >