< prev index next >

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

Print this page
@@ -1,7 +1,7 @@
  /*
-  * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved.
+  * Copyright (c) 1994, 2024, 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

@@ -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;

@@ -228,13 +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 final int ANNOTATION = 0x00002000;
+     private static final int ENUM       = 0x00004000;
+     private static final int SYNTHETIC  = 0x00001000;
  
      private static native void registerNatives();
      static {
          registerNatives();
      }

@@ -316,18 +317,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("value ");
+                 }
                  if (isInterface()) { // Note: all annotation interfaces are interfaces
                      sb.append("interface");
                  } else {
                      if (isEnum())
                          sb.append("enum");

@@ -630,10 +636,43 @@
          } else {
              return BootLoader.loadClass(module, name);
          }
      }
  
+     /**
+      * {@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; otherwise {@code false}}
+      *
+      * If this {@code Class} object represents an array type, an interface,
+      * a primitive type, or {@code void}, then this method returns {@code false}.
+      *
+      * @since Valhalla
+      */
+     @PreviewFeature(feature = PreviewFeature.Feature.VALUE_OBJECTS)
+     public boolean isValue() {
+         if (!PreviewFeatures.isEnabled()) {
+             return false;
+         }
+          if (isPrimitive() || isArray() || isInterface())
+              return false;
+         return ((getModifiers() & Modifier.IDENTITY) == 0);
+     }
+ 
      /**
       * {@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.

@@ -1421,13 +1460,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

@@ -1453,33 +1493,38 @@
          // 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);
+         int accessFlags = (location == AccessFlag.Location.CLASS) ?
+                 getClassAccessFlagsRaw() : getModifiers();
+         var cffv = ClassFileFormatVersion.fromMajor(getClassFileVersion() & 0xffff);
+         if (cffv.compareTo(ClassFileFormatVersion.latest()) >= 0) {
+             // Ignore unspecified (0x0800) access flag for current version
+             accessFlags &= ~0x0800;
+         }
+         if (!PreviewFeatures.isEnabled() && location == AccessFlag.Location.INNER_CLASS) {
+             accessFlags &= ~Modifier.IDENTITY; // drop ACC_IDENTITY bit in inner class if not in preview
+         }
+         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

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

@@ -4802,11 +4847,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.
       */
-     private int getClassFileVersion() {
+     /* package-private */
+     int getClassFileVersion() {
          Class<?> c = isArray() ? elementType() : this;
          return c.getClassFileVersion0();
      }
  
      private native int getClassFileVersion0();
< prev index next >