< prev index next > src/java.base/share/classes/jdk/internal/reflect/MethodHandleAccessorFactory.java
Print this page
/*
- * 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
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.*;
* 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);
} 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 >