< prev index next >

src/java.base/share/classes/java/lang/Class.java

Print this page
*** 36,10 ***
--- 36,11 ---
  import java.io.ObjectStreamField;
  import java.lang.reflect.AnnotatedElement;
  import java.lang.reflect.AnnotatedType;
  import java.lang.reflect.AccessFlag;
  import java.lang.reflect.Array;
+ import java.lang.reflect.ClassFileFormatVersion;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Executable;
  import java.lang.reflect.Field;
  import java.lang.reflect.GenericArrayType;
  import java.lang.reflect.GenericDeclaration;

*** 57,22 ***
--- 58,25 ---
  import java.security.ProtectionDomain;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.HashMap;
+ import java.util.HashSet;
  import java.util.LinkedHashMap;
  import java.util.LinkedHashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Objects;
  import java.util.Optional;
  import java.util.Set;
  import java.util.stream.Collectors;
  
  import jdk.internal.constant.ConstantUtils;
+ import jdk.internal.javac.PreviewFeature;
  import jdk.internal.loader.BootLoader;
  import jdk.internal.loader.BuiltinClassLoader;
+ import jdk.internal.misc.PreviewFeatures;
  import jdk.internal.misc.Unsafe;
  import jdk.internal.module.Resources;
  import jdk.internal.reflect.CallerSensitive;
  import jdk.internal.reflect.CallerSensitiveAdapter;
  import jdk.internal.reflect.ConstantPool;

*** 217,13 ***
                                GenericDeclaration,
                                Type,
                                AnnotatedElement,
                                TypeDescriptor.OfField<Class<?>>,
                                Constable {
!     private static final int ANNOTATION= 0x00002000;
!     private static final int ENUM      = 0x00004000;
!     private static final int SYNTHETIC = 0x00001000;
  
      private static native void registerNatives();
      static {
          runtimeSetup();
      }
--- 221,13 ---
                                GenericDeclaration,
                                Type,
                                AnnotatedElement,
                                TypeDescriptor.OfField<Class<?>>,
                                Constable {
!     private static final int ANNOTATION = 0x00002000;
!     private static final int ENUM       = 0x00004000;
!     private static final int SYNTHETIC  = 0x00001000;
  
      private static native void registerNatives();
      static {
          runtimeSetup();
      }

*** 238,19 ***
      /*
       * Private constructor. Only the Java Virtual Machine creates Class objects.
       * This constructor is not used and prevents the default constructor being
       * generated.
       */
!     private Class(ClassLoader loader, Class<?> arrayComponentType, char mods, ProtectionDomain pd, boolean isPrim, char flags) {
          // Initialize final field for classLoader.  The initialization value of non-null
          // prevents future JIT optimizations from assuming this final field is null.
          // The following assignments are done directly by the VM without calling this constructor.
          classLoader = loader;
          componentType = arrayComponentType;
          modifiers = mods;
          protectionDomain = pd;
          primitive = isPrim;
          classFileAccessFlags = flags;
      }
  
      /**
       * Converts the object to a string. The string representation is the
--- 242,20 ---
      /*
       * Private constructor. Only the Java Virtual Machine creates Class objects.
       * This constructor is not used and prevents the default constructor being
       * generated.
       */
!     private Class(ClassLoader loader, Class<?> arrayComponentType, char mods, ProtectionDomain pd, boolean isPrim, boolean isIdentity, char flags) {
          // Initialize final field for classLoader.  The initialization value of non-null
          // prevents future JIT optimizations from assuming this final field is null.
          // The following assignments are done directly by the VM without calling this constructor.
          classLoader = loader;
          componentType = arrayComponentType;
          modifiers = mods;
          protectionDomain = pd;
          primitive = isPrim;
+         identity = isIdentity;
          classFileAccessFlags = flags;
      }
  
      /**
       * Converts the object to a string. The string representation is the

*** 318,10 ***
--- 323,12 ---
                  } while (component.isArray());
                  sb.append(component.getName());
              } else {
                  // Class modifiers are a superset of interface modifiers
                  int modifiers = getModifiers() & Modifier.classModifiers();
+                 // Modifier.toString() below mis-interprets SYNCHRONIZED, STRICT, and VOLATILE bits
+                 modifiers &= ~(Modifier.SYNCHRONIZED | Modifier.STRICT | Modifier.VOLATILE);
                  if (modifiers != 0) {
                      sb.append(Modifier.toString(modifiers));
                      sb.append(' ');
                  }
  

*** 336,14 ***
                  if (isInterface()) { // Note: all annotation interfaces are interfaces
                      sb.append("interface");
                  } else {
                      if (isEnum())
                          sb.append("enum");
!                     else if (isRecord())
!                         sb.append("record");
!                     else
!                         sb.append("class");
                  }
                  sb.append(' ');
                  sb.append(getName());
              }
  
--- 343,19 ---
                  if (isInterface()) { // Note: all annotation interfaces are interfaces
                      sb.append("interface");
                  } else {
                      if (isEnum())
                          sb.append("enum");
!                     else {
!                         if (isValue()) {
!                             sb.append("value ");
!                         }
+                         if (isRecord())
+                             sb.append("record");
+                         else
+                             sb.append("class");
+                     }
                  }
                  sb.append(' ');
                  sb.append(getName());
              }
  

*** 609,10 ***
--- 621,58 ---
          } else {
              return BootLoader.loadClass(module, name);
          }
      }
  
+     /**
+      * {@return {@code true} if this {@code Class} object represents an identity class,
+      * otherwise {@code false}}
+      *
+      * <ul>
+      *      <li>
+      *          If this {@code Class} object represents an array type this method returns {@code true}.
+      *      <li>
+      *          If this {@code Class} object represents an interface, a primitive type,
+      *          or {@code void} this method returns {@code false}.
+      *      <li>
+      *          For all other {@code Class} objects, this method returns {@code true} if either
+      *          preview features are disabled or {@linkplain Modifier#IDENTITY} is set in the
+      *          {@linkplain #getModifiers() class modifiers}.
+      * </ul>
+      * @see AccessFlag#IDENTITY
+      * @since Valhalla
+      */
+     @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS, reflective=true)
+     public boolean isIdentity() {
+         return identity;
+     }
+ 
+     /**
+      * {@return {@code true} if this {@code Class} object represents a value class,
+      * otherwise {@code false}}
+      * <ul>
+      *      <li>
+      *          If this {@code Class} object represents an array type this method returns {@code false}.
+      *      <li>
+      *          If this {@code Class} object represents an interface, a primitive type,
+      *          or {@code void} this method returns {@code true} only if preview features are enabled.
+      *      <li>
+      *          For all other {@code Class} objects, this method returns {@code true} only if
+      *          preview features are enabled and {@linkplain Modifier#IDENTITY} is not set in the
+      *          {@linkplain #getModifiers() class modifiers}.
+      * </ul>
+      * @see AccessFlag#IDENTITY
+      * @since Valhalla
+      */
+     @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS, reflective=true)
+     public boolean isValue() {
+         if (!PreviewFeatures.isEnabled()) {
+             return false;
+         }
+         return !isIdentity();
+     }
+ 
      /**
       * {@return the {@code Class} object associated with the
       * {@linkplain #isPrimitive() primitive type} of the given name}
       * If the argument is not the name of a primitive type, {@code
       * null} is returned.

*** 1016,11 ***
  
      private transient Object classData; // Set by VM
      private transient Object[] signers; // Read by VM, mutable
      private final transient char modifiers;  // Set by the VM
      private final transient char classFileAccessFlags;  // Set by the VM
!     private final transient boolean primitive;  // Set by the VM if the Class is a primitive type.
  
      // package-private
      Object getClassData() {
          return classData;
      }
--- 1076,12 ---
  
      private transient Object classData; // Set by VM
      private transient Object[] signers; // Read by VM, mutable
      private final transient char modifiers;  // Set by the VM
      private final transient char classFileAccessFlags;  // Set by the VM
!     private final transient boolean primitive;  // Set by the VM if the Class is a primitive type
+     private final transient boolean identity;   // Set by the VM if the Class is an identity class
  
      // package-private
      Object getClassData() {
          return classData;
      }

*** 1336,10 ***
--- 1397,11 ---
       *      modifiers are the same as those of its component type
       * <li> its {@code abstract} and {@code final} modifiers are always
       *      {@code true}
       * <li> its interface modifier is always {@code false}, even when
       *      the component type is an interface
+      * <li> its {@code identity} modifier is always true
       * </ul>
       * If this {@code Class} object represents a primitive type or
       * void, its {@code public}, {@code abstract}, and {@code final}
       * modifiers are always {@code true}.
       * For {@code Class} objects representing void, primitive types, and

*** 1360,21 ***
       * @jls 9.1.1 Interface Modifiers
       * @jvms 4.1 The {@code ClassFile} Structure
       */
      public int getModifiers() { return modifiers; }
  
!     /**
       * {@return an unmodifiable set of the {@linkplain AccessFlag access
       * flags} for this class, possibly empty}
       *
       * <p> If the underlying class is an array class:
       * <ul>
       * <li> its {@code PUBLIC}, {@code PRIVATE} and {@code PROTECTED}
       *      access flags are the same as those of its component type
       * <li> its {@code ABSTRACT} and {@code FINAL} flags are present
       * <li> its {@code INTERFACE} flag is absent, even when the
       *      component type is an interface
       * </ul>
       * If this {@code Class} object represents a primitive type or
       * void, the flags are {@code PUBLIC}, {@code ABSTRACT}, and
       * {@code FINAL}.
       * For {@code Class} objects representing void, primitive types, and
--- 1422,23 ---
       * @jls 9.1.1 Interface Modifiers
       * @jvms 4.1 The {@code ClassFile} Structure
       */
      public int getModifiers() { return modifiers; }
  
!    /**
       * {@return an unmodifiable set of the {@linkplain AccessFlag access
       * flags} for this class, possibly empty}
+      * The {@code AccessFlags} may depend on the class file format version of the class.
       *
       * <p> If the underlying class is an array class:
       * <ul>
       * <li> its {@code PUBLIC}, {@code PRIVATE} and {@code PROTECTED}
       *      access flags are the same as those of its component type
       * <li> its {@code ABSTRACT} and {@code FINAL} flags are present
       * <li> its {@code INTERFACE} flag is absent, even when the
       *      component type is an interface
+     * <li> its {@code identity} modifier is always true
       * </ul>
       * If this {@code Class} object represents a primitive type or
       * void, the flags are {@code PUBLIC}, {@code ABSTRACT}, and
       * {@code FINAL}.
       * For {@code Class} objects representing void, primitive types, and

*** 1388,26 ***
      public Set<AccessFlag> accessFlags() {
          // Location.CLASS allows SUPER and AccessFlag.MODULE which
          // INNER_CLASS forbids. INNER_CLASS allows PRIVATE, PROTECTED,
          // and STATIC, which are not allowed on Location.CLASS.
          // Use getClassFileAccessFlags to expose SUPER status.
          var location = (isMemberClass() || isLocalClass() ||
                          isAnonymousClass() || isArray()) ?
              AccessFlag.Location.INNER_CLASS :
              AccessFlag.Location.CLASS;
!         return getReflectionFactory().parseAccessFlags((location == AccessFlag.Location.CLASS) ?
!                         getClassFileAccessFlags() : getModifiers(), location, this);
      }
  
!     /**
       * Gets the signers of this class.
       *
       * @return  the signers of this class, or null if there are no signers.  In
       *          particular, this method returns null if this {@code Class} object represents
       *          a primitive type or void.
       * @since   1.1
       */
      public Object[] getSigners() {
          var signers = this.signers;
          return signers == null ? null : signers.clone();
      }
  
--- 1452,36 ---
      public Set<AccessFlag> accessFlags() {
          // Location.CLASS allows SUPER and AccessFlag.MODULE which
          // INNER_CLASS forbids. INNER_CLASS allows PRIVATE, PROTECTED,
          // and STATIC, which are not allowed on Location.CLASS.
          // Use getClassFileAccessFlags to expose SUPER status.
+         // Arrays need to use PRIVATE/PROTECTED from its component modifiers.
          var location = (isMemberClass() || isLocalClass() ||
                          isAnonymousClass() || isArray()) ?
              AccessFlag.Location.INNER_CLASS :
              AccessFlag.Location.CLASS;
!         int accessFlags = location == AccessFlag.Location.CLASS ? getClassFileAccessFlags() : getModifiers();
!         var reflectionFactory = getReflectionFactory();
+         var ans = reflectionFactory.parseAccessFlags(accessFlags, location, this);
+         if (PreviewFeatures.isEnabled() && reflectionFactory.classFileFormatVersion(this) != ClassFileFormatVersion.CURRENT_PREVIEW_FEATURES
+                 && isIdentity()) {
+             var set = new HashSet<>(ans);
+             set.add(AccessFlag.IDENTITY);
+             return Set.copyOf(set);
+         }
+         return ans;
      }
  
!    /**
       * Gets the signers of this class.
       *
       * @return  the signers of this class, or null if there are no signers.  In
       *          particular, this method returns null if this {@code Class} object represents
       *          a primitive type or void.
       * @since   1.1
       */
+ 
      public Object[] getSigners() {
          var signers = this.signers;
          return signers == null ? null : signers.clone();
      }
  

*** 3777,11 ***
       *
       * @return an array representing the superinterfaces
       * @since 1.8
       */
      public AnnotatedType[] getAnnotatedInterfaces() {
!          return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this);
      }
  
      private native Class<?> getNestHost0();
  
      /**
--- 3851,11 ---
       *
       * @return an array representing the superinterfaces
       * @since 1.8
       */
      public AnnotatedType[] getAnnotatedInterfaces() {
!         return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this);
      }
  
      private native Class<?> getNestHost0();
  
      /**

*** 4117,10 ***
--- 4191,11 ---
       *
       * If the class is an array type then the class file version of its element
       * type is returned.  If the class is a primitive type then the latest class
       * file major version is returned and zero is returned for the minor version.
       */
+     /* package-private */
      int getClassFileVersion() {
          Class<?> c = isArray() ? elementType() : this;
          return c.getClassFileVersion0();
      }
  
< prev index next >