1 /*
  2  * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 
 26 package jdk.internal.reflect;
 27 
 28 import java.io.Externalizable;
 29 import java.io.ObjectInputStream;
 30 import java.io.ObjectOutputStream;
 31 import java.io.ObjectStreamClass;
 32 import java.io.ObjectStreamField;
 33 import java.io.OptionalDataException;
 34 import java.io.Serializable;
 35 import java.lang.classfile.ClassFile;
 36 import java.lang.invoke.MethodHandle;
 37 import java.lang.invoke.MethodHandles;
 38 import java.lang.reflect.*;
 39 import java.util.Set;
 40 
 41 import jdk.internal.access.JavaLangReflectAccess;
 42 import jdk.internal.access.SharedSecrets;
 43 import jdk.internal.misc.VM;
 44 import jdk.internal.vm.annotation.Stable;
 45 
 46 /** <P> The master factory for all reflective objects, both those in
 47     java.lang.reflect (Fields, Methods, Constructors) as well as their
 48     delegates (FieldAccessors, MethodAccessors, ConstructorAccessors).
 49     </P>
 50 
 51     <P> The methods in this class are extremely unsafe and can cause
 52     subversion of both the language and the verifier. For this reason,
 53     they are all instance methods, and access to the constructor of
 54     this factory is guarded by a security check, in similar style to
 55     {@link jdk.internal.misc.Unsafe}. </P>
 56 */
 57 
 58 public class ReflectionFactory {
 59 
 60     private static final ReflectionFactory soleInstance = new ReflectionFactory();
 61 
 62 
 63     /* Method for static class initializer <clinit>, or null */
 64     private static volatile Method hasStaticInitializerMethod;
 65 
 66     private final JavaLangReflectAccess langReflectAccess;
 67 
 68     private ReflectionFactory() {
 69         this.langReflectAccess = SharedSecrets.getJavaLangReflectAccess();
 70     }
 71 
 72     /**
 73      * Provides the caller with the capability to instantiate reflective
 74      * objects.
 75      *
 76      * <p> The returned <code>ReflectionFactory</code> object should be
 77      * carefully guarded by the caller, since it can be used to read and
 78      * write private data and invoke private methods, as well as to load
 79      * unverified bytecodes.  It must never be passed to untrusted code.
 80      */
 81     public static ReflectionFactory getReflectionFactory() {
 82         return soleInstance;
 83     }
 84 
 85     //--------------------------------------------------------------------------
 86     //
 87     // Routines used by java.lang.reflect
 88     //
 89     //
 90 
 91     /*
 92      * Note: this routine can cause the declaring class for the field
 93      * be initialized and therefore must not be called until the
 94      * first get/set of this field.
 95      * @param field the field
 96      * @param override true if caller has overridden accessibility
 97      */
 98     public FieldAccessor newFieldAccessor(Field field, boolean override) {
 99         Field root = langReflectAccess.getRoot(field);
100         if (root != null) {
101             // FieldAccessor will use the root unless the modifiers have
102             // been overridden
103             if (root.getModifiers() == field.getModifiers() || !override) {
104                 field = root;
105             }
106         }
107         boolean isFinal = Modifier.isFinal(field.getModifiers());
108         boolean isReadOnly = isFinal && (!override || langReflectAccess.isTrustedFinalField(field));
109         return MethodHandleAccessorFactory.newFieldAccessor(field, isReadOnly);
110     }
111 
112     public MethodAccessor newMethodAccessor(Method method, boolean callerSensitive) {
113         // use the root Method that will not cache caller class
114         Method root = langReflectAccess.getRoot(method);
115         if (root != null) {
116             method = root;
117         }
118 
119         return MethodHandleAccessorFactory.newMethodAccessor(method, callerSensitive);
120     }
121 
122     public ConstructorAccessor newConstructorAccessor(Constructor<?> c) {
123         Class<?> declaringClass = c.getDeclaringClass();
124         if (Modifier.isAbstract(declaringClass.getModifiers())) {
125             return new InstantiationExceptionConstructorAccessorImpl(null);
126         }
127         if (declaringClass == Class.class) {
128             return new InstantiationExceptionConstructorAccessorImpl
129                 ("Can not instantiate java.lang.Class");
130         }
131 
132         // use the root Constructor that will not cache caller class
133         Constructor<?> root = langReflectAccess.getRoot(c);
134         if (root != null) {
135             c = root;
136         }
137 
138         return MethodHandleAccessorFactory.newConstructorAccessor(c);
139     }
140 
141     //--------------------------------------------------------------------------
142     //
143     // Routines used by java.lang
144     //
145     //
146 
147     /** Makes a copy of the passed method. The returned method is a
148         "child" of the passed one; see the comments in Method.java for
149         details. */
150     public Method copyMethod(Method arg) {
151         return langReflectAccess.copyMethod(arg);
152     }
153 
154     /** Makes a copy of the passed method. The returned method is NOT
155      * a "child" but a "sibling" of the Method in arg. Should only be
156      * used on non-root methods. */
157     public Method leafCopyMethod(Method arg) {
158         Method root = langReflectAccess.getRoot(arg);
159         return langReflectAccess.copyMethod(root);
160     }
161 
162     /** Makes a copy of the passed field. The returned field is a
163         "child" of the passed one; see the comments in Field.java for
164         details. */
165     public Field copyField(Field arg) {
166         return langReflectAccess.copyField(arg);
167     }
168 
169     /** Makes a copy of the passed constructor. The returned
170         constructor is a "child" of the passed one; see the comments
171         in Constructor.java for details. */
172     public <T> Constructor<T> copyConstructor(Constructor<T> arg) {
173         return langReflectAccess.copyConstructor(arg);
174     }
175 
176     /** Gets the byte[] that encodes TypeAnnotations on an executable.
177      */
178     public byte[] getExecutableTypeAnnotationBytes(Executable ex) {
179         return langReflectAccess.getExecutableTypeAnnotationBytes(ex);
180     }
181 
182     public Class<?>[] getExecutableSharedParameterTypes(Executable ex) {
183         return langReflectAccess.getExecutableSharedParameterTypes(ex);
184     }
185 
186     public <T> T newInstance(Constructor<T> ctor, Object[] args, Class<?> caller)
187         throws IllegalAccessException, InstantiationException, InvocationTargetException
188     {
189         return langReflectAccess.newInstance(ctor, args, caller);
190     }
191 
192     //--------------------------------------------------------------------------
193     //
194     // Routines used by serialization
195     //
196     //
197 
198     public final Constructor<?> newConstructorForExternalization(Class<?> cl) {
199         if (!Externalizable.class.isAssignableFrom(cl)) {
200             return null;
201         }
202         if (cl.isValue()) {
203             throw new UnsupportedOperationException("newConstructorForExternalization does not support value classes");
204         }
205         try {
206             Constructor<?> cons = cl.getConstructor();
207             cons.setAccessible(true);
208             return cons;
209         } catch (NoSuchMethodException ex) {
210             return null;
211         }
212     }
213 
214     public final Constructor<?> newConstructorForSerialization(Class<?> cl,
215                                                                Constructor<?> constructorToCall)
216     {
217         if (constructorToCall.getDeclaringClass() == cl) {
218             constructorToCall.setAccessible(true);
219             return constructorToCall;
220         }
221         if (cl.isValue()) {
222             throw new UnsupportedOperationException("newConstructorForSerialization does not support value classes");
223         }
224         return generateConstructor(cl, constructorToCall);
225     }
226 
227     /**
228      * Given a class, determines whether its superclass has
229      * any constructors that are accessible from the class.
230      * This is a special purpose method intended to do access
231      * checking for a serializable class and its superclasses
232      * up to, but not including, the first non-serializable
233      * superclass. This also implies that the superclass is
234      * always non-null, because a serializable class must be a
235      * class (not an interface) and Object is not serializable.
236      *
237      * @param cl the class from which access is checked
238      * @return whether the superclass has a constructor accessible from cl
239      */
240     private boolean superHasAccessibleConstructor(Class<?> cl) {
241         Class<?> superCl = cl.getSuperclass();
242         assert Serializable.class.isAssignableFrom(cl);
243         assert superCl != null;
244         if (packageEquals(cl, superCl)) {
245             // accessible if any non-private constructor is found
246             for (Constructor<?> ctor : superCl.getDeclaredConstructors()) {
247                 if ((ctor.getModifiers() & Modifier.PRIVATE) == 0) {
248                     return true;
249                 }
250             }
251             if (Reflection.areNestMates(cl, superCl)) {
252                 return true;
253             }
254             return false;
255         } else {
256             // sanity check to ensure the parent is protected or public
257             if ((superCl.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) == 0) {
258                 return false;
259             }
260             // accessible if any constructor is protected or public
261             for (Constructor<?> ctor : superCl.getDeclaredConstructors()) {
262                 if ((ctor.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) != 0) {
263                     return true;
264                 }
265             }
266             return false;
267         }
268     }
269 
270     /**
271      * Returns a constructor that allocates an instance of cl and that then initializes
272      * the instance by calling the no-arg constructor of its first non-serializable
273      * superclass. This is specified in the Serialization Specification, section 3.1,
274      * in step 11 of the deserialization process. If cl is not serializable, returns
275      * cl's no-arg constructor. If no accessible constructor is found, or if the
276      * class hierarchy is somehow malformed (e.g., a serializable class has no
277      * superclass), null is returned.
278      *
279      * @param cl the class for which a constructor is to be found
280      * @return the generated constructor, or null if none is available
281      */
282     public final Constructor<?> newConstructorForSerialization(Class<?> cl) {
283         if (cl.isValue()) {
284             throw new UnsupportedOperationException("newConstructorForSerialization does not support value classes: " + cl);
285         }
286 
287         Class<?> initCl = cl;
288         while (Serializable.class.isAssignableFrom(initCl)) {
289             Class<?> prev = initCl;
290             if ((initCl = initCl.getSuperclass()) == null ||
291                 (!disableSerialConstructorChecks() && !superHasAccessibleConstructor(prev))) {
292                 return null;
293             }
294         }
295         Constructor<?> constructorToCall;
296         try {
297             constructorToCall = initCl.getDeclaredConstructor();
298             int mods = constructorToCall.getModifiers();
299             if ((mods & Modifier.PRIVATE) != 0 ||
300                     ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
301                             !packageEquals(cl, initCl))) {
302                 return null;
303             }
304         } catch (NoSuchMethodException ex) {
305             return null;
306         }
307         return generateConstructor(cl, constructorToCall);
308     }
309 
310     private final Constructor<?> generateConstructor(Class<?> cl,
311                                                      Constructor<?> constructorToCall) {
312         ConstructorAccessor acc = MethodHandleAccessorFactory
313                 .newSerializableConstructorAccessor(cl, constructorToCall);
314         // Unlike other root constructors, this constructor is not copied for mutation
315         // but directly mutated, as it is not cached. To cache this constructor,
316         // setAccessible call must be done on a copy and return that copy instead.
317         Constructor<?> ctor = langReflectAccess.newConstructorWithAccessor(constructorToCall, acc);
318         ctor.setAccessible(true);
319         return ctor;
320     }
321 
322     public final MethodHandle readObjectForSerialization(Class<?> cl) {
323         return findReadWriteObjectForSerialization(cl, "readObject", ObjectInputStream.class);
324     }
325 
326     public final MethodHandle readObjectNoDataForSerialization(Class<?> cl) {
327         return findReadWriteObjectForSerialization(cl, "readObjectNoData", null);
328     }
329 
330     public final MethodHandle writeObjectForSerialization(Class<?> cl) {
331         return findReadWriteObjectForSerialization(cl, "writeObject", ObjectOutputStream.class);
332     }
333 
334     private final MethodHandle findReadWriteObjectForSerialization(Class<?> cl,
335                                                                    String methodName,
336                                                                    Class<?> streamClass) {
337         if (!Serializable.class.isAssignableFrom(cl)) {
338             return null;
339         }
340 
341         try {
342             Method meth = streamClass == null ? cl.getDeclaredMethod(methodName)
343                     : cl.getDeclaredMethod(methodName, streamClass);
344             int mods = meth.getModifiers();
345             if (meth.getReturnType() != Void.TYPE ||
346                     Modifier.isStatic(mods) ||
347                     !Modifier.isPrivate(mods)) {
348                 return null;
349             }
350             meth.setAccessible(true);
351             return MethodHandles.lookup().unreflect(meth);
352         } catch (NoSuchMethodException ex) {
353             return null;
354         } catch (IllegalAccessException ex1) {
355             throw new InternalError("Error", ex1);
356         }
357     }
358 
359     public final MethodHandle defaultReadObjectForSerialization(Class<?> cl) {
360         if (hasDefaultOrNoSerialization(cl)) {
361             return null;
362         }
363 
364         return SharedSecrets.getJavaObjectStreamReflectionAccess().defaultReadObject(cl);
365     }
366 
367     public final MethodHandle defaultWriteObjectForSerialization(Class<?> cl) {
368         if (hasDefaultOrNoSerialization(cl)) {
369             return null;
370         }
371 
372         return SharedSecrets.getJavaObjectStreamReflectionAccess().defaultWriteObject(cl);
373     }
374 
375     /**
376      * These are specific leaf classes which appear to be Serializable, but which
377      * have special semantics according to the serialization specification. We
378      * could theoretically include array classes here, but it is easier and clearer
379      * to just use `Class#isArray` instead.
380      */
381     private static final Set<Class<?>> nonSerializableLeafClasses = Set.of(
382         Class.class,
383         String.class,
384         ObjectStreamClass.class
385     );
386 
387     private static boolean hasDefaultOrNoSerialization(Class<?> cl) {
388         return ! Serializable.class.isAssignableFrom(cl)
389             || cl.isInterface()
390             || cl.isArray()
391             || Proxy.isProxyClass(cl)
392             || Externalizable.class.isAssignableFrom(cl)
393             || cl.isEnum()
394             || cl.isRecord()
395             || cl.isHidden()
396             || nonSerializableLeafClasses.contains(cl);
397     }
398 
399     /**
400      * Returns a MethodHandle for {@code writeReplace} on the serializable class
401      * or null if no match found.
402      * @param cl a serializable class
403      * @return the {@code writeReplace} MethodHandle or {@code null} if not found
404      */
405     public final MethodHandle writeReplaceForSerialization(Class<?> cl) {
406         return getReplaceResolveForSerialization(cl, "writeReplace");
407     }
408 
409     /**
410      * Returns a MethodHandle for {@code readResolve} on the serializable class
411      * or null if no match found.
412      * @param cl a serializable class
413      * @return the {@code writeReplace} MethodHandle or {@code null} if not found
414      */
415     public final MethodHandle readResolveForSerialization(Class<?> cl) {
416         return getReplaceResolveForSerialization(cl, "readResolve");
417     }
418 
419     /**
420      * Lookup readResolve or writeReplace on a class with specified
421      * signature constraints.
422      * @param cl a serializable class
423      * @param methodName the method name to find
424      * @return a MethodHandle for the method or {@code null} if not found or
425      *       has the wrong signature.
426      */
427     private MethodHandle getReplaceResolveForSerialization(Class<?> cl,
428                                                            String methodName) {
429         if (!Serializable.class.isAssignableFrom(cl)) {
430             return null;
431         }
432 
433         Class<?> defCl = cl;
434         while (defCl != null) {
435             try {
436                 Method m = defCl.getDeclaredMethod(methodName);
437                 if (m.getReturnType() != Object.class) {
438                     return null;
439                 }
440                 int mods = m.getModifiers();
441                 if (Modifier.isStatic(mods) | Modifier.isAbstract(mods)) {
442                     return null;
443                 } else if (Modifier.isPublic(mods) | Modifier.isProtected(mods)) {
444                     // fall through
445                 } else if (Modifier.isPrivate(mods) && (cl != defCl)) {
446                     return null;
447                 } else if (!packageEquals(cl, defCl)) {
448                     return null;
449                 }
450                 try {
451                     // Normal return
452                     m.setAccessible(true);
453                     return MethodHandles.lookup().unreflect(m);
454                 } catch (IllegalAccessException ex0) {
455                     // setAccessible should prevent IAE
456                     throw new InternalError("Error", ex0);
457                 }
458             } catch (NoSuchMethodException ex) {
459                 defCl = defCl.getSuperclass();
460             }
461         }
462         return null;
463     }
464 
465     /**
466      * Returns true if the given class defines a static initializer method,
467      * false otherwise.
468      */
469     public final boolean hasStaticInitializerForSerialization(Class<?> cl) {
470         Method m = hasStaticInitializerMethod;
471         if (m == null) {
472             try {
473                 m = ObjectStreamClass.class.getDeclaredMethod("hasStaticInitializer",
474                         new Class<?>[]{Class.class});
475                 m.setAccessible(true);
476                 hasStaticInitializerMethod = m;
477             } catch (NoSuchMethodException ex) {
478                 throw new InternalError("No such method hasStaticInitializer on "
479                         + ObjectStreamClass.class, ex);
480             }
481         }
482         try {
483             return (Boolean) m.invoke(null, cl);
484         } catch (InvocationTargetException | IllegalAccessException ex) {
485             throw new InternalError("Exception invoking hasStaticInitializer", ex);
486         }
487     }
488 
489     /**
490      * Return the accessible constructor for OptionalDataException signaling eof.
491      * @return the eof constructor for OptionalDataException
492      */
493     public final Constructor<OptionalDataException> newOptionalDataExceptionForSerialization() {
494         try {
495             Constructor<OptionalDataException> boolCtor =
496                     OptionalDataException.class.getDeclaredConstructor(Boolean.TYPE);
497             boolCtor.setAccessible(true);
498             return boolCtor;
499         } catch (NoSuchMethodException ex) {
500             throw new InternalError("Constructor not found", ex);
501         }
502     }
503 
504     public final ObjectStreamField[] serialPersistentFields(Class<?> cl) {
505         if (! Serializable.class.isAssignableFrom(cl) || cl.isInterface() || cl.isEnum()) {
506             return null;
507         }
508 
509         try {
510             Field field = cl.getDeclaredField("serialPersistentFields");
511             int mods = field.getModifiers();
512             if (! (Modifier.isStatic(mods) && Modifier.isPrivate(mods) && Modifier.isFinal(mods))) {
513                 return null;
514             }
515             if (field.getType() != ObjectStreamField[].class) {
516                 return null;
517             }
518             field.setAccessible(true);
519             ObjectStreamField[] array = (ObjectStreamField[]) field.get(null);
520             return array != null && array.length > 0 ? array.clone() : array;
521         } catch (ReflectiveOperationException e) {
522             return null;
523         }
524     }
525 
526     public final Set<AccessFlag> parseAccessFlags(int mask, AccessFlag.Location location, Class<?> classFile) {
527         var cffv = classFileFormatVersion(classFile);
528         return cffv == null ?
529                 AccessFlag.maskToAccessFlags(mask, location) :
530                 AccessFlag.maskToAccessFlags(mask, location, cffv);
531     }
532 
533     private final ClassFileFormatVersion classFileFormatVersion(Class<?> cl) {
534         int raw = SharedSecrets.getJavaLangAccess().classFileVersion(cl);
535 
536         int major = raw & 0xFFFF;
537         int minor = raw >>> Character.SIZE;
538 
539         assert VM.isSupportedClassFileVersion(major, minor) : major + "." + minor;
540 
541         if (major >= ClassFile.JAVA_12_VERSION) {
542             if (minor == 0)
543                 return ClassFileFormatVersion.fromMajor(raw);
544             return null; // preview or old preview, fallback to default handling
545         } else if (major == ClassFile.JAVA_1_VERSION) {
546             return minor < 3 ? ClassFileFormatVersion.RELEASE_0 : ClassFileFormatVersion.RELEASE_1;
547         }
548         return ClassFileFormatVersion.fromMajor(major);
549     }
550 
551     //--------------------------------------------------------------------------
552     //
553     // Internals only below this point
554     //
555 
556     /*
557      * If -Djdk.reflect.useNativeAccessorOnly is set, use the native accessor only.
558      * For testing purpose only.
559      */
560     static boolean useNativeAccessorOnly() {
561         return config().useNativeAccessorOnly;
562     }
563 
564     private static boolean disableSerialConstructorChecks() {
565         return config().disableSerialConstructorChecks;
566     }
567 
568     /**
569      * The configuration is lazily initialized after the module system is initialized. The
570      * default config would be used before the proper config is loaded.
571      *
572      * The static initializer of ReflectionFactory is run before the system properties are set up.
573      * The class initialization is caused by the class initialization of java.lang.reflect.Method
574      * (more properly, caused by the class initialization for java.lang.reflect.AccessibleObject)
575      * that happens very early VM startup, initPhase1.
576      */
577     private static @Stable Config config;
578 
579     private static final Config DEFAULT_CONFIG = new Config(false, // useNativeAccessorOnly
580                                                             false); // disableSerialConstructorChecks
581 
582     /**
583      * The configurations for the reflection factory. Configurable via
584      * system properties but only available after ReflectionFactory is
585      * loaded during early VM startup.
586      *
587      * Note that the default implementations of the object methods of
588      * this Config record (toString, equals, hashCode) use indy,
589      * which is available to use only after initPhase1. These methods
590      * are currently not called, but should they be needed, a workaround
591      * is to override them.
592      */
593     private record Config(boolean useNativeAccessorOnly,
594                           boolean disableSerialConstructorChecks) {
595     }
596 
597     private static Config config() {
598         Config c = config;
599         if (c != null) {
600             return c;
601         }
602 
603         // Always use the default configuration until the module system is initialized.
604         if (!VM.isModuleSystemInited()) {
605             return DEFAULT_CONFIG;
606         }
607 
608         return config = loadConfig();
609     }
610 
611     private static Config loadConfig() {
612         assert VM.isModuleSystemInited();
613 
614         boolean useNativeAccessorOnly =
615             "true".equals(System.getProperty("jdk.reflect.useNativeAccessorOnly"));
616         boolean disableSerialConstructorChecks =
617             "true".equals(System.getProperty("jdk.disableSerialConstructorChecks"));
618 
619         return new Config(useNativeAccessorOnly, disableSerialConstructorChecks);
620     }
621 
622     /**
623      * Returns true if classes are defined in the classloader and same package, false
624      * otherwise.
625      * @param cl1 a class
626      * @param cl2 another class
627      * @return true if the two classes are in the same classloader and package
628      */
629     private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
630         assert !cl1.isArray() && !cl2.isArray();
631 
632         if (cl1 == cl2) {
633             return true;
634         }
635 
636         return cl1.getClassLoader() == cl2.getClassLoader() &&
637                 cl1.getPackageName() == cl2.getPackageName();
638     }
639 }