diff --git a/src/java.base/share/classes/java/lang/reflect/Constructor.java b/src/java.base/share/classes/java/lang/reflect/Constructor.java index 99f14d01536..668fc575688 100644 --- a/src/java.base/share/classes/java/lang/reflect/Constructor.java +++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java @@ -165,6 +165,14 @@ public final class Constructor extends Executable { return res; } + // Creates a new root constructor with a custom accessor for serialization hooks. + Constructor newWithAccessor(ConstructorAccessor accessor) { + var res = new Constructor<>(clazz, parameterTypes, exceptionTypes, modifiers, slot, + signature, annotations, parameterAnnotations); + res.constructorAccessor = accessor; + return res; + } + /** * {@inheritDoc} * diff --git a/src/java.base/share/classes/java/lang/reflect/Method.java b/src/java.base/share/classes/java/lang/reflect/Method.java index 80e0209249c..9b929509882 100644 --- a/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/src/java.base/share/classes/java/lang/reflect/Method.java @@ -173,21 +173,6 @@ public final class Method extends Executable { return res; } - /** - * Make a copy of a leaf method. - */ - Method leafCopy() { - if (this.root == null) - throw new IllegalArgumentException("Can only leafCopy a non-root Method"); - - Method res = new Method(clazz, name, parameterTypes, returnType, - exceptionTypes, modifiers, slot, signature, - annotations, parameterAnnotations, annotationDefault); - res.root = root; - res.methodAccessor = methodAccessor; - return res; - } - /** * @throws InaccessibleObjectException {@inheritDoc} * @throws SecurityException {@inheritDoc} diff --git a/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java b/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java index f815862edf6..835ffef616e 100644 --- a/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java +++ b/src/java.base/share/classes/java/lang/reflect/ReflectAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -25,65 +25,15 @@ package java.lang.reflect; -import jdk.internal.reflect.MethodAccessor; +import jdk.internal.access.JavaLangReflectAccess; import jdk.internal.reflect.ConstructorAccessor; /** Package-private class implementing the jdk.internal.access.JavaLangReflectAccess interface, allowing the java.lang package to instantiate objects in this package. */ - -class ReflectAccess implements jdk.internal.access.JavaLangReflectAccess { - public Constructor newConstructor(Class declaringClass, - Class[] parameterTypes, - Class[] checkedExceptions, - int modifiers, - int slot, - String signature, - byte[] annotations, - byte[] parameterAnnotations) - { - return new Constructor<>(declaringClass, - parameterTypes, - checkedExceptions, - modifiers, - slot, - signature, - annotations, - parameterAnnotations); - } - - public MethodAccessor getMethodAccessor(Method m) { - return m.getMethodAccessor(); - } - - public void setMethodAccessor(Method m, MethodAccessor accessor) { - m.setMethodAccessor(accessor); - } - - public ConstructorAccessor getConstructorAccessor(Constructor c) { - return c.getConstructorAccessor(); - } - - public void setConstructorAccessor(Constructor c, - ConstructorAccessor accessor) - { - c.setConstructorAccessor(accessor); - } - - public int getConstructorSlot(Constructor c) { - return c.getSlot(); - } - - public String getConstructorSignature(Constructor c) { - return c.getSignature(); - } - - public byte[] getConstructorAnnotations(Constructor c) { - return c.getRawAnnotations(); - } - - public byte[] getConstructorParameterAnnotations(Constructor c) { - return c.getRawParameterAnnotations(); +final class ReflectAccess implements JavaLangReflectAccess { + public Constructor newConstructorWithAccessor(Constructor original, ConstructorAccessor accessor) { + return original.newWithAccessor(accessor); } public byte[] getExecutableTypeAnnotationBytes(Executable ex) { @@ -105,9 +55,6 @@ class ReflectAccess implements jdk.internal.access.JavaLangReflectAccess { public Method copyMethod(Method arg) { return arg.copy(); } - public Method leafCopyMethod(Method arg) { - return arg.leafCopy(); - } public Field copyField(Field arg) { return arg.copy(); diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java index f49221e44ed..d0c415d2dc6 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangReflectAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -29,67 +29,29 @@ import java.lang.reflect.*; import jdk.internal.reflect.*; /** An interface which gives privileged packages Java-level access to - internals of java.lang.reflect. */ - + internals of java.lang.reflect. Use as a last resort! */ public interface JavaLangReflectAccess { - /** Creates a new java.lang.reflect.Constructor. Access checks as - per java.lang.reflect.AccessibleObject are not overridden. */ - public Constructor newConstructor(Class declaringClass, - Class[] parameterTypes, - Class[] checkedExceptions, - int modifiers, - int slot, - String signature, - byte[] annotations, - byte[] parameterAnnotations); - - /** Gets the MethodAccessor object for a java.lang.reflect.Method */ - public MethodAccessor getMethodAccessor(Method m); - - /** Sets the MethodAccessor object for a java.lang.reflect.Method */ - public void setMethodAccessor(Method m, MethodAccessor accessor); - - /** Gets the ConstructorAccessor object for a - java.lang.reflect.Constructor */ - public ConstructorAccessor getConstructorAccessor(Constructor c); - - /** Sets the ConstructorAccessor object for a - java.lang.reflect.Constructor */ - public void setConstructorAccessor(Constructor c, - ConstructorAccessor accessor); + /** + * Creates a new root constructor from the original one, with + * a custom accessor. Used by serialization hooks. + */ + Constructor newConstructorWithAccessor(Constructor original, ConstructorAccessor accessor); /** Gets the byte[] that encodes TypeAnnotations on an Executable. */ public byte[] getExecutableTypeAnnotationBytes(Executable ex); - /** Gets the "slot" field from a Constructor (used for serialization) */ - public int getConstructorSlot(Constructor c); - - /** Gets the "signature" field from a Constructor (used for serialization) */ - public String getConstructorSignature(Constructor c); - - /** Gets the "annotations" field from a Constructor (used for serialization) */ - public byte[] getConstructorAnnotations(Constructor c); - - /** Gets the "parameterAnnotations" field from a Constructor (used for serialization) */ - public byte[] getConstructorParameterAnnotations(Constructor c); - /** Gets the shared array of parameter types of an Executable. */ public Class[] getExecutableSharedParameterTypes(Executable ex); /** Gets the shared array of exception types of an Executable. */ public Class[] getExecutableSharedExceptionTypes(Executable ex); - // // Copying routines, needed to quickly fabricate new Field, // Method, and Constructor objects from templates - // /** Makes a "child" copy of a Method */ public Method copyMethod(Method arg); - /** Makes a copy of this non-root a Method */ - public Method leafCopyMethod(Method arg); - /** Makes a "child" copy of a Field */ public Field copyField(Field arg); diff --git a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java index 0dacbef993a..5acafe01a89 100644 --- a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java +++ b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java @@ -53,7 +53,13 @@ import javax.security.auth.x500.X500Principal; within that package; the object implementing that interface is provided through a third package to which access is restricted. This framework avoids the primary disadvantage of using reflection - for this purpose, namely the loss of compile-time checking. */ + for this purpose, namely the loss of compile-time checking. + *

+ * Usage of these APIs often means bad encapsulation designs, + * increased complexity and lack of sustainability. + * Use this only as a last resort! + * + */ public class SharedSecrets { private static JavaAWTAccess javaAWTAccess; diff --git a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java index 2222c810524..9a31c5402d4 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java +++ b/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -179,41 +179,6 @@ public class ReflectionFactory { // // - /** Creates a new java.lang.reflect.Constructor. Access checks as - per java.lang.reflect.AccessibleObject are not overridden. */ - public Constructor newConstructor(Class declaringClass, - Class[] parameterTypes, - Class[] checkedExceptions, - int modifiers, - int slot, - String signature, - byte[] annotations, - byte[] parameterAnnotations) - { - return langReflectAccess.newConstructor(declaringClass, - parameterTypes, - checkedExceptions, - modifiers, - slot, - signature, - annotations, - parameterAnnotations); - } - - /** Gets the ConstructorAccessor object for a - java.lang.reflect.Constructor */ - public ConstructorAccessor getConstructorAccessor(Constructor c) { - return langReflectAccess.getConstructorAccessor(c); - } - - /** Sets the ConstructorAccessor object for a - java.lang.reflect.Constructor */ - public void setConstructorAccessor(Constructor c, - ConstructorAccessor accessor) - { - langReflectAccess.setConstructorAccessor(c, accessor); - } - /** Makes a copy of the passed method. The returned method is a "child" of the passed one; see the comments in Method.java for details. */ @@ -225,10 +190,10 @@ public class ReflectionFactory { * a "child" but a "sibling" of the Method in arg. Should only be * used on non-root methods. */ public Method leafCopyMethod(Method arg) { - return langReflectAccess.leafCopyMethod(arg); + Method root = langReflectAccess.getRoot(arg); + return langReflectAccess.copyMethod(root); } - /** Makes a copy of the passed field. The returned field is a "child" of the passed one; see the comments in Field.java for details. */ @@ -369,15 +334,6 @@ public class ReflectionFactory { private final Constructor generateConstructor(Class cl, Constructor constructorToCall) { - - Constructor ctor = newConstructor(constructorToCall.getDeclaringClass(), - constructorToCall.getParameterTypes(), - constructorToCall.getExceptionTypes(), - constructorToCall.getModifiers(), - langReflectAccess.getConstructorSlot(constructorToCall), - langReflectAccess.getConstructorSignature(constructorToCall), - langReflectAccess.getConstructorAnnotations(constructorToCall), - langReflectAccess.getConstructorParameterAnnotations(constructorToCall)); ConstructorAccessor acc; if (useOldSerializableConstructor()) { acc = new SerializationConstructorAccessorGenerator(). @@ -386,9 +342,12 @@ public class ReflectionFactory { constructorToCall.getModifiers(), constructorToCall.getDeclaringClass()); } else { - acc = MethodHandleAccessorFactory.newSerializableConstructorAccessor(cl, ctor); + acc = MethodHandleAccessorFactory.newSerializableConstructorAccessor(cl, constructorToCall); } - setConstructorAccessor(ctor, acc); + // Unlike other root constructors, this constructor is not copied for mutation + // but directly mutated, as it is not cached. To cache this constructor, + // setAccessible call must be done on a copy and return that copy instead. + Constructor ctor = langReflectAccess.newConstructorWithAccessor(constructorToCall, acc); ctor.setAccessible(true); return ctor; }