< prev index next >

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

Print this page
*** 1,7 ***
  /*
!  * Copyright (c) 2021, 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
--- 1,7 ---
  /*
!  * 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 ***
       * 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
       */
      static ConstructorAccessorImpl newSerializableConstructorAccessor(Class<?> decl, Constructor<?> ctor) {
!         if (!constructorInSuperclass(decl, ctor)) {
-             throw new UnsupportedOperationException(ctor + " not a superclass of " + decl.getName());
-         }
  
          // 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);
--- 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) {
!         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 ***
          } catch (IllegalAccessException e) {
              throw new InternalError(e);
          }
      }
  
!     private static boolean constructorInSuperclass(Class<?> decl, Constructor<?> ctor) {
          if (decl == ctor.getDeclaringClass())
!             return true;
  
          Class<?> cl = decl;
!         while ((cl = cl.getSuperclass()) != null) {
              if (cl == ctor.getDeclaringClass()) {
!                 return true;
              }
!         }
!         return false;
      }
  
      private static MethodHandle makeConstructorHandle(MethodHandle ctor) {
          int paramCount = ctor.type().parameterCount();
          MethodHandle target = ctor.asFixedArity();
--- 136,32 ---
          } catch (IllegalAccessException e) {
              throw new InternalError(e);
          }
      }
  
!     /// 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())
!             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;
!         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;
              }
!         } 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 >