< prev index next >

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

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

@@ -37,10 +37,11 @@
  
  import jdk.internal.access.JavaLangInvokeAccess;
  import jdk.internal.access.SharedSecrets;
  import jdk.internal.misc.Unsafe;
  import jdk.internal.misc.VM;
+ import jdk.internal.value.ValueClass;
  
  import static java.lang.invoke.MethodType.genericMethodType;
  import static java.lang.invoke.MethodType.methodType;
  import static jdk.internal.reflect.MethodHandleAccessorFactory.LazyStaticHolder.*;
  

@@ -115,15 +116,17 @@
       * of the given class and instantiated by the given constructor.
       *
       * @param decl the class to instantiate
       * @param ctor the constructor to call
       * @return an accessible constructor
+      * @throws UnsupportedOperationException if the constructor is not from
+      *         a superclass, if the instantiated class is a value class, or if
+      *         any superclass between the declaring class of the constructor and
+      *         the instantiated class declares a strict instance field
       */
      static ConstructorAccessorImpl newSerializableConstructorAccessor(Class<?> decl, Constructor<?> ctor) {
-         if (!constructorInSuperclass(decl, ctor)) {
-             throw new UnsupportedOperationException(ctor + " not a superclass of " + decl.getName());
-         }
+         validateSerializableConstructor(decl, ctor);
  
          // ExceptionInInitializerError may be thrown during class initialization
          // Ensure class initialized outside the invocation of method handle
          // so that EIIE is propagated (not wrapped with ITE)
          ensureClassInitialized(decl);

@@ -133,21 +136,32 @@
          } catch (IllegalAccessException e) {
              throw new InternalError(e);
          }
      }
  
-     private static boolean constructorInSuperclass(Class<?> decl, Constructor<?> ctor) {
+     /// Ensures a constructor is a valid super constructor to call for the serializable class {@code decl}
+     /// according to the serialization specification.
+     /// 1. The initialized class must not be a concrete value class (the superclasses may be abstract value)
+     /// 2. There should be no strict field initialization skipped by the constructor
+     private static void validateSerializableConstructor(Class<?> decl, Constructor<?> ctor) {
          if (decl == ctor.getDeclaringClass())
-             return true;
+             throw new UnsupportedOperationException("Attempt to duplicate " + ctor);
+         if (decl.isValue())
+             throw new UnsupportedOperationException("Cannot generate serialization constructor for value class " + decl.getTypeName());
  
          Class<?> cl = decl;
-         while ((cl = cl.getSuperclass()) != null) {
+         do {
+             if (ValueClass.hasStrictInstanceField(cl)) {
+                 throw new UnsupportedOperationException("Class " + cl.getTypeName() + " between " + ctor + " and "
+                         + decl.getTypeName() + " declares a strictly-initialized instance field");
+             }
+             cl = cl.getSuperclass();
              if (cl == ctor.getDeclaringClass()) {
-                 return true;
+                 return;
              }
-         }
-         return false;
+         } while (cl != null);
+         throw new UnsupportedOperationException(ctor + " not a superclass of " + decl.getName());
      }
  
      private static MethodHandle makeConstructorHandle(MethodHandle ctor) {
          int paramCount = ctor.type().parameterCount();
          MethodHandle target = ctor.asFixedArity();
< prev index next >