< prev index next >

src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java

Print this page
@@ -1,7 +1,7 @@
  /*
-  * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
+  * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Oracle designates this

@@ -30,19 +30,19 @@
  import java.io.ObjectOutputStream;
  import java.io.ObjectStreamClass;
  import java.io.ObjectStreamField;
  import java.io.OptionalDataException;
  import java.io.Serializable;
- import java.lang.classfile.ClassFile;
  import java.lang.invoke.MethodHandle;
  import java.lang.invoke.MethodHandles;
  import java.lang.reflect.*;
  import java.util.Set;
  
  import jdk.internal.access.JavaLangReflectAccess;
  import jdk.internal.access.SharedSecrets;
  import jdk.internal.misc.VM;
+ import jdk.internal.value.ValueClass;
  import jdk.internal.vm.annotation.Stable;
  
  /** <P> The master factory for all reflective objects, both those in
      java.lang.reflect (Fields, Methods, Constructors) as well as their
      delegates (FieldAccessors, MethodAccessors, ConstructorAccessors).

@@ -103,11 +103,11 @@
              if (root.getModifiers() == field.getModifiers() || !override) {
                  field = root;
              }
          }
          boolean isFinal = Modifier.isFinal(field.getModifiers());
-         boolean isReadOnly = isFinal && (!override || langReflectAccess.isTrustedFinalField(field));
+         boolean isReadOnly = isFinal && (!override || langReflectAccess.isTrustedFinalField(field) || field.isStrictInit());
          return MethodHandleAccessorFactory.newFieldAccessor(field, isReadOnly);
      }
  
      public MethodAccessor newMethodAccessor(Method method, boolean callerSensitive) {
          // use the root Method that will not cache caller class

@@ -197,10 +197,13 @@
  
      public final Constructor<?> newConstructorForExternalization(Class<?> cl) {
          if (!Externalizable.class.isAssignableFrom(cl)) {
              return null;
          }
+         if (cl.isValue()) {
+             throw new UnsupportedOperationException("newConstructorForExternalization does not support value classes");
+         }
          try {
              Constructor<?> cons = cl.getConstructor();
              cons.setAccessible(true);
              return cons;
          } catch (NoSuchMethodException ex) {

@@ -213,10 +216,11 @@
      {
          if (constructorToCall.getDeclaringClass() == cl) {
              constructorToCall.setAccessible(true);
              return constructorToCall;
          }
+ 
          return generateConstructor(cl, constructorToCall);
      }
  
      /**
       * Given a class, determines whether its superclass has

@@ -266,20 +270,25 @@
       * the instance by calling the no-arg constructor of its first non-serializable
       * superclass. This is specified in the Serialization Specification, section 3.1,
       * in step 11 of the deserialization process. If cl is not serializable, returns
       * cl's no-arg constructor. If no accessible constructor is found, or if the
       * class hierarchy is somehow malformed (e.g., a serializable class has no
-      * superclass), null is returned.
+      * superclass), or if this serializable class or a serializable superclass
+      * declares a strictly-initialized non-static field, null is returned.
       *
       * @param cl the class for which a constructor is to be found
       * @return the generated constructor, or null if none is available
       */
      public final Constructor<?> newConstructorForSerialization(Class<?> cl) {
+         if (cl.isValue()) {
+             return null;
+         }
+ 
          Class<?> initCl = cl;
          while (Serializable.class.isAssignableFrom(initCl)) {
              Class<?> prev = initCl;
-             if ((initCl = initCl.getSuperclass()) == null ||
+             if ((initCl = initCl.getSuperclass()) == null || ValueClass.hasStrictInstanceField(prev) ||
                  (!disableSerialConstructorChecks() && !superHasAccessibleConstructor(prev))) {
                  return null;
              }
          }
          Constructor<?> constructorToCall;

@@ -292,11 +301,12 @@
                  return null;
              }
          } catch (NoSuchMethodException ex) {
              return null;
          }
-         return generateConstructor(cl, constructorToCall);
+ 
+         return newConstructorForSerialization(cl, constructorToCall);
      }
  
      private final Constructor<?> generateConstructor(Class<?> cl,
                                                       Constructor<?> constructorToCall) {
          ConstructorAccessor acc = MethodHandleAccessorFactory

@@ -511,35 +521,10 @@
          } catch (ReflectiveOperationException e) {
              return null;
          }
      }
  
-     public final Set<AccessFlag> parseAccessFlags(int mask, AccessFlag.Location location, Class<?> classFile) {
-         var cffv = classFileFormatVersion(classFile);
-         return cffv == null ?
-                 AccessFlag.maskToAccessFlags(mask, location) :
-                 AccessFlag.maskToAccessFlags(mask, location, cffv);
-     }
- 
-     private final ClassFileFormatVersion classFileFormatVersion(Class<?> cl) {
-         int raw = SharedSecrets.getJavaLangAccess().classFileVersion(cl);
- 
-         int major = raw & 0xFFFF;
-         int minor = raw >>> Character.SIZE;
- 
-         assert VM.isSupportedClassFileVersion(major, minor) : major + "." + minor;
- 
-         if (major >= ClassFile.JAVA_12_VERSION) {
-             if (minor == 0)
-                 return ClassFileFormatVersion.fromMajor(raw);
-             return null; // preview or old preview, fallback to default handling
-         } else if (major == ClassFile.JAVA_1_VERSION) {
-             return minor < 3 ? ClassFileFormatVersion.RELEASE_0 : ClassFileFormatVersion.RELEASE_1;
-         }
-         return ClassFileFormatVersion.fromMajor(major);
-     }
- 
      //--------------------------------------------------------------------------
      //
      // Internals only below this point
      //
  
< prev index next >