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