< prev index next > src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java
Print this page
/*
- * 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
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).
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
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) {
{
if (constructorToCall.getDeclaringClass() == cl) {
constructorToCall.setAccessible(true);
return constructorToCall;
}
+
return generateConstructor(cl, constructorToCall);
}
/**
* Given a class, determines whether its superclass has
* 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;
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
} 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 >