< prev index next >

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

Print this page
*** 37,10 ***
--- 37,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;

*** 79,10 ***
--- 80,11 ---
  import jdk.internal.reflect.CallerSensitive;
  import jdk.internal.reflect.CallerSensitiveAdapter;
  import jdk.internal.reflect.ConstantPool;
  import jdk.internal.reflect.Reflection;
  import jdk.internal.reflect.ReflectionFactory;
+ import jdk.internal.value.PrimitiveClass;
  import jdk.internal.vm.annotation.ForceInline;
  import jdk.internal.vm.annotation.IntrinsicCandidate;
  
  import sun.invoke.util.Wrapper;
  import sun.reflect.generics.factory.CoreReflectionFactory;

*** 227,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 {
          registerNatives();
      }
--- 229,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 {
          registerNatives();
      }

*** 261,12 ***
       * this method returns "class " followed by {@code getName}.
       *
       * @return a string representation of this {@code Class} object.
       */
      public String toString() {
!         String kind = isInterface() ? "interface " : isPrimitive() ? "" : "class ";
!         return kind.concat(getName());
      }
  
      /**
       * Returns a string describing this {@code Class}, including
       * information about modifiers and type parameters.
--- 263,26 ---
       * this method returns "class " followed by {@code getName}.
       *
       * @return a string representation of this {@code Class} object.
       */
      public String toString() {
!         String s = getName();
!         if (isPrimitive()) {
+             return s;
+         }
+         // Avoid invokedynamic based String concat, might be not available
+         // Prepend type of class
+         s = (isInterface() ? "interface " : "class ").concat(s);
+         if (isValue()) {
+             // prepend value class type
+             s = (isPrimitiveClass() ? "primitive " : "value ").concat(s);
+             if (isPrimitiveClass() && isPrimaryType()) {
+                 // Append .ref
+                 s = s.concat(".ref");
+             }
+         }
+         return s;
      }
  
      /**
       * Returns a string describing this {@code Class}, including
       * information about modifiers and type parameters.

*** 315,18 ***
--- 331,23 ---
                  } 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(' ');
                  }
  
                  if (isAnnotation()) {
                      sb.append('@');
                  }
+                 if (isValue()) {
+                     sb.append(isPrimitiveClass() ? "primitive " : "value ");
+                 }
                  if (isInterface()) { // Note: all annotation interfaces are interfaces
                      sb.append("interface");
                  } else {
                      if (isEnum())
                          sb.append("enum");

*** 537,12 ***
          return forName0(name, initialize, loader, caller);
      }
  
      /** Called after security check for system loader access checks have been made. */
      private static native Class<?> forName0(String name, boolean initialize,
!                                             ClassLoader loader,
!                                             Class<?> caller)
          throws ClassNotFoundException;
  
  
      /**
       * Returns the {@code Class} with the given {@linkplain ClassLoader##binary-name
--- 558,12 ---
          return forName0(name, initialize, loader, caller);
      }
  
      /** Called after security check for system loader access checks have been made. */
      private static native Class<?> forName0(String name, boolean initialize,
!                                     ClassLoader loader,
!                                     Class<?> caller)
          throws ClassNotFoundException;
  
  
      /**
       * Returns the {@code Class} with the given {@linkplain ClassLoader##binary-name

*** 629,10 ***
--- 650,148 ---
          } else {
              return BootLoader.loadClass(module, name);
          }
      }
  
+     // set by VM if this class is an exotic type such as primitive class
+     // otherwise, these two fields are null
+     private transient Class<T> primaryType;
+     private transient Class<T> secondaryType;
+ 
+     /**
+      * Returns {@code true} if this class is a primitive class.
+      * <p>
+      * Each primitive class has a {@linkplain #isPrimaryType() primary type}
+      * representing the <em>primitive reference type</em> and a
+      * {@linkplain #isPrimitiveValueType() secondary type} representing
+      * the <em>primitive value type</em>.  The primitive reference type
+      * and primitive value type can be obtained by calling the
+      * {@link #asPrimaryType()} and {@link #asValueType} method
+      * of a primitive class respectively.
+      * <p>
+      * A primitive class is a {@linkplain #isValue() value class}.
+      *
+      * @return {@code true} if this class is a primitive class, otherwise {@code false}
+      * @see #isValue()
+      * @see #asPrimaryType()
+      * @see #asValueType()
+      * @since Valhalla
+      */
+     /* package */ boolean isPrimitiveClass() {
+         return (this.getModifiers() & PrimitiveClass.PRIMITIVE_CLASS) != 0;
+     }
+ 
+     /**
+      * {@return {@code true} if this {@code Class} object represents an identity
+      * class or interface; otherwise {@code false}}
+      *
+      * If this {@code Class} object represents an array type, then this method
+      * returns {@code true}.
+      * If this {@code Class} object represents a primitive type, or {@code void},
+      * then this method returns {@code false}.
+      *
+      * @since Valhalla
+      */
+     @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS)
+     public native boolean isIdentity();
+ 
+     /**
+      * {@return {@code true} if this {@code Class} object represents a value
+      * class or interface; otherwise {@code false}}
+      *
+      * If this {@code Class} object represents an array type, a primitive type, or
+      * {@code void}, then this method returns {@code false}.
+      *
+      * @since Valhalla
+      */
+     @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS)
+     public boolean isValue() {
+         return (this.getModifiers() & Modifier.VALUE) != 0;
+     }
+ 
+     /**
+      * Returns a {@code Class} object representing the primary type
+      * of this class or interface.
+      * <p>
+      * If this {@code Class} object represents a primitive type or an array type,
+      * then this method returns this class.
+      * <p>
+      * If this {@code Class} object represents a {@linkplain #isPrimitiveClass()
+      * primitive class}, then this method returns the <em>primitive reference type</em>
+      * type of this primitive class.
+      * <p>
+      * Otherwise, this {@code Class} object represents a non-primitive class or interface
+      * and this method returns this class.
+      *
+      * @return the {@code Class} representing the primary type of
+      *         this class or interface
+      * @since Valhalla
+      */
+     @IntrinsicCandidate
+     /* package */ Class<?> asPrimaryType() {
+         return isPrimitiveClass() ? primaryType : this;
+     }
+ 
+     /**
+      * Returns a {@code Class} object representing the <em>primitive value type</em>
+      * of this class if this class is a {@linkplain #isPrimitiveClass() primitive class}.
+      *
+      * @apiNote Alternatively, this method returns null if this class is not
+      *          a primitive class rather than throwing UOE.
+      *
+      * @return the {@code Class} representing the {@linkplain #isPrimitiveValueType()
+      * primitive value type} of this class if this class is a primitive class
+      * @throws UnsupportedOperationException if this class or interface
+      *         is not a primitive class
+      * @since Valhalla
+      */
+     @IntrinsicCandidate
+     /* package */ Class<?> asValueType() {
+         if (isPrimitiveClass())
+             return secondaryType;
+ 
+         throw new UnsupportedOperationException(this.getName().concat(" is not a primitive class"));
+     }
+ 
+     /**
+      * Returns {@code true} if this {@code Class} object represents the primary type
+      * of this class or interface.
+      * <p>
+      * If this {@code Class} object represents a primitive type or an array type,
+      * then this method returns {@code true}.
+      * <p>
+      * If this {@code Class} object represents a {@linkplain #isPrimitiveClass()
+      * primitive}, then this method returns {@code true} if this {@code Class}
+      * object represents a primitive reference type, or returns {@code false}
+      * if this {@code Class} object represents a primitive value type.
+      * <p>
+      * If this {@code Class} object represents a non-primitive class or interface,
+      * then this method returns {@code true}.
+      *
+      * @return {@code true} if this {@code Class} object represents
+      * the primary type of this class or interface
+      * @since Valhalla
+      */
+     /* package */ boolean isPrimaryType() {
+         if (isPrimitiveClass()) {
+             return this == primaryType;
+         }
+         return true;
+     }
+ 
+     /**
+      * Returns {@code true} if this {@code Class} object represents
+      * a {@linkplain #isPrimitiveClass() primitive} value type.
+      *
+      * @return {@code true} if this {@code Class} object represents
+      * the value type of a primitive class
+      * @since Valhalla
+      */
+     /* package */ boolean isPrimitiveValueType() {
+         return isPrimitiveClass() && this == secondaryType;
+     }
+ 
      /**
       * {@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.

*** 1385,10 ***
--- 1544,12 ---
       * in an integer. The modifiers consist of the Java Virtual Machine's
       * constants for {@code public}, {@code protected},
       * {@code private}, {@code final}, {@code static},
       * {@code abstract} and {@code interface}; they should be decoded
       * using the methods of class {@code Modifier}.
+      * The modifiers also include the Java Virtual Machine's constants for
+      * {@code identity class} and {@code value class}.
       *
       * <p> If the underlying class is an array class:
       * <ul>
       * <li> its {@code public}, {@code private} and {@code protected}
       *      modifiers are the same as those of its component type

*** 1419,13 ***
       * @jvms 4.1 The {@code ClassFile} Structure
       */
      @IntrinsicCandidate
      public native int getModifiers();
  
!     /**
       * {@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
--- 1580,14 ---
       * @jvms 4.1 The {@code ClassFile} Structure
       */
      @IntrinsicCandidate
      public native int getModifiers();
  
!    /**
       * {@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

*** 1451,33 ***
          // Use getClassAccessFlagsRaw to expose SUPER status.
          var location = (isMemberClass() || isLocalClass() ||
                          isAnonymousClass() || isArray()) ?
              AccessFlag.Location.INNER_CLASS :
              AccessFlag.Location.CLASS;
!         return AccessFlag.maskToAccessFlags((location == AccessFlag.Location.CLASS) ?
!                                             getClassAccessFlagsRaw() :
!                                             getModifiers(),
!                                             location);
      }
  
!     /**
       * 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 native Object[] getSigners();
  
- 
      /**
       * Set the signers of this class.
       */
      native void setSigners(Object[] signers);
  
- 
      /**
       * If this {@code Class} object represents a local or anonymous
       * class within a method, returns a {@link
       * java.lang.reflect.Method Method} object representing the
       * immediately enclosing method of the underlying class. Returns
--- 1613,35 ---
          // Use getClassAccessFlagsRaw to expose SUPER status.
          var location = (isMemberClass() || isLocalClass() ||
                          isAnonymousClass() || isArray()) ?
              AccessFlag.Location.INNER_CLASS :
              AccessFlag.Location.CLASS;
!         int accessFlags = (location == AccessFlag.Location.CLASS) ?
!                 getClassAccessFlagsRaw() : getModifiers();
!         var cffv = ClassFileFormatVersion.fromMajor(getClassFileVersion() & 0xffff);
!         if (cffv.compareTo(ClassFileFormatVersion.latest()) >= 0) {
+             // Ignore unspecified (0x800) access flag for current version
+             accessFlags &= ~0x0800;
+         }
+         return AccessFlag.maskToAccessFlags(accessFlags, location, cffv);
      }
  
!    /**
       * 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 native Object[] getSigners();
  
      /**
       * Set the signers of this class.
       */
      native void setSigners(Object[] signers);
  
      /**
       * If this {@code Class} object represents a local or anonymous
       * class within a method, returns a {@link
       * java.lang.reflect.Method Method} object representing the
       * immediately enclosing method of the underlying class. Returns

*** 1614,13 ***
  
          boolean isPartial() {
              return enclosingClass == null || name == null || descriptor == null;
          }
  
!         boolean isConstructor() { return !isPartial() && ConstantDescs.INIT_NAME.equals(name); }
  
!         boolean isMethod() { return !isPartial() && !isConstructor() && !ConstantDescs.CLASS_INIT_NAME.equals(name); }
  
          Class<?> getEnclosingClass() { return enclosingClass; }
  
          String getName() { return name; }
  
--- 1778,17 ---
  
          boolean isPartial() {
              return enclosingClass == null || name == null || descriptor == null;
          }
  
!         boolean isObjectConstructor() { return !isPartial() && ConstantDescs.INIT_NAME.equals(name); }
  
!         boolean isValueFactoryMethod() { return !isPartial() && ConstantDescs.VNEW_NAME.equals(name); }
+ 
+         boolean isMethod() { return !isPartial() && !isObjectConstructor()
+                                         && !isValueFactoryMethod()
+                                         && !ConstantDescs.CLASS_INIT_NAME.equals(name); }
  
          Class<?> getEnclosingClass() { return enclosingClass; }
  
          String getName() { return name; }
  

*** 1673,11 ***
          EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo();
  
          if (enclosingInfo == null)
              return null;
          else {
!             if (!enclosingInfo.isConstructor())
                  return null;
  
              ConstructorRepository typeInfo = ConstructorRepository.make(enclosingInfo.getDescriptor(),
                                                                          getFactory());
              Type []    parameterTypes   = typeInfo.getParameterTypes();
--- 1841,11 ---
          EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo();
  
          if (enclosingInfo == null)
              return null;
          else {
!             if (!enclosingInfo.isObjectConstructor() && !enclosingInfo.isValueFactoryMethod())
                  return null;
  
              ConstructorRepository typeInfo = ConstructorRepository.make(enclosingInfo.getDescriptor(),
                                                                          getFactory());
              Type []    parameterTypes   = typeInfo.getParameterTypes();

*** 1856,14 ***
                  int dimensions = 0;
                  do {
                      dimensions++;
                      cl = cl.getComponentType();
                  } while (cl.isArray());
!                 return cl.getName().concat("[]".repeat(dimensions));
              } catch (Throwable e) { /*FALLTHRU*/ }
          }
!         return getName();
      }
  
      /**
       * Returns the canonical name of the underlying class as
       * defined by <cite>The Java Language Specification</cite>.
--- 2024,19 ---
                  int dimensions = 0;
                  do {
                      dimensions++;
                      cl = cl.getComponentType();
                  } while (cl.isArray());
!                 return cl.getTypeName().concat("[]".repeat(dimensions));
              } catch (Throwable e) { /*FALLTHRU*/ }
          }
!         if (isPrimitiveClass()) {
+             // TODO: null-default
+             return isPrimaryType() ? getName().concat(".ref") : getName();
+         } else {
+             return getName();
+         }
      }
  
      /**
       * Returns the canonical name of the underlying class as
       * defined by <cite>The Java Language Specification</cite>.

*** 3799,11 ***
              if (arrayContentsEq(parameterTypes,
                                  fact.getExecutableSharedParameterTypes(constructor))) {
                  return constructor;
              }
          }
!         throw new NoSuchMethodException(methodToString("<init>", parameterTypes));
      }
  
      //
      // Other helpers and base implementation
      //
--- 3972,11 ---
              if (arrayContentsEq(parameterTypes,
                                  fact.getExecutableSharedParameterTypes(constructor))) {
                  return constructor;
              }
          }
!         throw new NoSuchMethodException(methodToString(isValue() ? "<vnew>" : "<init>", parameterTypes));
      }
  
      //
      // Other helpers and base implementation
      //

*** 4104,10 ***
--- 4277,13 ---
       * @since 1.5
       */
      @SuppressWarnings("unchecked")
      @IntrinsicCandidate
      public T cast(Object obj) {
+         if (isPrimitiveValueType() && obj == null)
+             throw new NullPointerException(getName() + " is a primitive value type");
+ 
          if (obj != null && !isInstance(obj))
              throw new ClassCastException(cannotCastMsg(obj));
          return (T) obj;
      }
  

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

*** 4609,24 ***
          if (isPrimitive())
              return Wrapper.forPrimitiveType(this).basicTypeString();
  
          if (isArray()) {
              return "[" + componentType.descriptorString();
!         } else if (isHidden()) {
              String name = getName();
              int index = name.indexOf('/');
              return new StringBuilder(name.length() + 2)
!                     .append('L')
                      .append(name.substring(0, index).replace('.', '/'))
                      .append('.')
                      .append(name, index + 1, name.length())
                      .append(';')
                      .toString();
          } else {
              String name = getName().replace('.', '/');
              return new StringBuilder(name.length() + 2)
!                     .append('L')
                      .append(name)
                      .append(';')
                      .toString();
          }
      }
--- 4785,26 ---
          if (isPrimitive())
              return Wrapper.forPrimitiveType(this).basicTypeString();
  
          if (isArray()) {
              return "[" + componentType.descriptorString();
!         }
+         char typeDesc = isPrimitiveValueType() ? 'Q' : 'L';
+         if (isHidden()) {
              String name = getName();
              int index = name.indexOf('/');
              return new StringBuilder(name.length() + 2)
!                     .append(typeDesc)
                      .append(name.substring(0, index).replace('.', '/'))
                      .append('.')
                      .append(name, index + 1, name.length())
                      .append(';')
                      .toString();
          } else {
              String name = getName().replace('.', '/');
              return new StringBuilder(name.length() + 2)
!                     .append(typeDesc)
                      .append(name)
                      .append(';')
                      .toString();
          }
      }

*** 4800,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.
       */
!     private int getClassFileVersion() {
          Class<?> c = isArray() ? elementType() : this;
          return c.getClassFileVersion0();
      }
  
      private native int getClassFileVersion0();
--- 4978,12 ---
       *
       * 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();
      }
  
      private native int getClassFileVersion0();
< prev index next >