1 /*
  2  * Copyright (c) 2001, 2021, 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.OptionalDataException;
 33 import java.io.Serializable;
 34 import java.lang.invoke.MethodHandle;
 35 import java.lang.invoke.MethodHandles;
 36 import java.lang.reflect.Constructor;
 37 import java.lang.reflect.Executable;
 38 import java.lang.reflect.Field;
 39 import java.lang.reflect.InvocationTargetException;
 40 import java.lang.reflect.Method;
 41 import java.lang.reflect.Modifier;
 42 import java.security.PrivilegedAction;
 43 import java.util.Properties;
 44 import jdk.internal.access.JavaLangReflectAccess;
 45 import jdk.internal.access.SharedSecrets;
 46 import jdk.internal.misc.VM;
 47 import sun.security.action.GetPropertyAction;
 48 import sun.security.util.SecurityConstants;
 49 
 50 /** <P> The master factory for all reflective objects, both those in
 51     java.lang.reflect (Fields, Methods, Constructors) as well as their
 52     delegates (FieldAccessors, MethodAccessors, ConstructorAccessors).
 53     </P>
 54 
 55     <P> The methods in this class are extremely unsafe and can cause
 56     subversion of both the language and the verifier. For this reason,
 57     they are all instance methods, and access to the constructor of
 58     this factory is guarded by a security check, in similar style to
 59     {@link jdk.internal.misc.Unsafe}. </P>
 60 */
 61 
 62 public class ReflectionFactory {
 63 
 64     private static boolean initted = false;
 65     private static final ReflectionFactory soleInstance = new ReflectionFactory();
 66 
 67 
 68     /* Method for static class initializer <clinit>, or null */
 69     private static volatile Method hasStaticInitializerMethod;
 70 
 71     //
 72     // "Inflation" mechanism. Loading bytecodes to implement
 73     // Method.invoke() and Constructor.newInstance() currently costs
 74     // 3-4x more than an invocation via native code for the first
 75     // invocation (though subsequent invocations have been benchmarked
 76     // to be over 20x faster). Unfortunately this cost increases
 77     // startup time for certain applications that use reflection
 78     // intensively (but only once per class) to bootstrap themselves.
 79     // To avoid this penalty we reuse the existing JVM entry points
 80     // for the first few invocations of Methods and Constructors and
 81     // then switch to the bytecode-based implementations.
 82     //
 83     // Package-private to be accessible to NativeMethodAccessorImpl
 84     // and NativeConstructorAccessorImpl
 85     private static boolean noInflation        = false;
 86     private static int     inflationThreshold = 15;
 87 
 88     // true if deserialization constructor checking is disabled
 89     private static boolean disableSerialConstructorChecks = false;
 90 
 91     private final JavaLangReflectAccess langReflectAccess;
 92     private ReflectionFactory() {
 93         this.langReflectAccess = SharedSecrets.getJavaLangReflectAccess();
 94     }
 95 
 96     /**
 97      * A convenience class for acquiring the capability to instantiate
 98      * reflective objects.  Use this instead of a raw call to {@link
 99      * #getReflectionFactory} in order to avoid being limited by the
100      * permissions of your callers.
101      *
102      * <p>An instance of this class can be used as the argument of
103      * <code>AccessController.doPrivileged</code>.
104      */
105     public static final class GetReflectionFactoryAction
106         implements PrivilegedAction<ReflectionFactory> {
107         public ReflectionFactory run() {
108             return getReflectionFactory();
109         }
110     }
111 
112     /**
113      * Provides the caller with the capability to instantiate reflective
114      * objects.
115      *
116      * <p> First, if there is a security manager, its
117      * <code>checkPermission</code> method is called with a {@link
118      * java.lang.RuntimePermission} with target
119      * <code>"reflectionFactoryAccess"</code>.  This may result in a
120      * security exception.
121      *
122      * <p> The returned <code>ReflectionFactory</code> object should be
123      * carefully guarded by the caller, since it can be used to read and
124      * write private data and invoke private methods, as well as to load
125      * unverified bytecodes.  It must never be passed to untrusted code.
126      *
127      * @exception SecurityException if a security manager exists and its
128      *             <code>checkPermission</code> method doesn't allow
129      *             access to the RuntimePermission "reflectionFactoryAccess".  */
130     public static ReflectionFactory getReflectionFactory() {
131         @SuppressWarnings("removal")
132         SecurityManager security = System.getSecurityManager();
133         if (security != null) {
134             security.checkPermission(
135                 SecurityConstants.REFLECTION_FACTORY_ACCESS_PERMISSION);
136         }
137         return soleInstance;
138     }
139 
140     /**
141      * Returns an alternate reflective Method instance for the given method
142      * intended for reflection to invoke, if present.
143      *
144      * A trusted method can define an alternate implementation for a method `foo`
145      * by defining a method named "reflected$foo" that will be invoked
146      * reflectively.
147      */
148     private static Method findMethodForReflection(Method method) {
149         String altName = "reflected$" + method.getName();
150         try {
151            return method.getDeclaringClass()
152                         .getDeclaredMethod(altName, method.getParameterTypes());
153         } catch (NoSuchMethodException ex) {
154             return null;
155         }
156     }
157 
158     //--------------------------------------------------------------------------
159     //
160     // Routines used by java.lang.reflect
161     //
162     //
163 
164     /*
165      * Note: this routine can cause the declaring class for the field
166      * be initialized and therefore must not be called until the
167      * first get/set of this field.
168      * @param field the field
169      * @param override true if caller has overridden accessibility
170      */
171     public FieldAccessor newFieldAccessor(Field field, boolean override) {
172         checkInitted();
173 
174         Field root = langReflectAccess.getRoot(field);
175         if (root != null) {
176             // FieldAccessor will use the root unless the modifiers have
177             // been overridden
178             if (root.getModifiers() == field.getModifiers() || !override) {
179                 field = root;
180             }
181         }
182         boolean isFinal = Modifier.isFinal(field.getModifiers());
183         boolean isReadOnly = isFinal && (!override || langReflectAccess.isTrustedFinalField(field));
184         return UnsafeFieldAccessorFactory.newFieldAccessor(field, isReadOnly);
185     }
186 
187     public MethodAccessor newMethodAccessor(Method method) {
188         checkInitted();
189 
190         if (Reflection.isCallerSensitive(method)) {
191             Method altMethod = findMethodForReflection(method);
192             if (altMethod != null) {
193                 method = altMethod;
194             }
195         }
196 
197         // use the root Method that will not cache caller class
198         Method root = langReflectAccess.getRoot(method);
199         if (root != null) {
200             method = root;
201         }
202 
203         if (noInflation && !method.getDeclaringClass().isHidden()) {
204             return new MethodAccessorGenerator().
205                 generateMethod(method.getDeclaringClass(),
206                                method.getName(),
207                                method.getParameterTypes(),
208                                method.getReturnType(),
209                                method.getExceptionTypes(),
210                                method.getModifiers());
211         } else {
212             NativeMethodAccessorImpl acc = new NativeMethodAccessorImpl(method);
213             return acc.getParent();
214         }
215     }
216 
217     public ConstructorAccessor newConstructorAccessor(Constructor<?> c) {
218         checkInitted();
219 
220         Class<?> declaringClass = c.getDeclaringClass();
221         if (Modifier.isAbstract(declaringClass.getModifiers())) {
222             return new InstantiationExceptionConstructorAccessorImpl(null);
223         }
224         if (declaringClass == Class.class) {
225             return new InstantiationExceptionConstructorAccessorImpl
226                 ("Can not instantiate java.lang.Class");
227         }
228 
229         // use the root Constructor that will not cache caller class
230         Constructor<?> root = langReflectAccess.getRoot(c);
231         if (root != null) {
232             c = root;
233         }
234 
235         // Bootstrapping issue: since we use Class.newInstance() in
236         // the ConstructorAccessor generation process, we have to
237         // break the cycle here.
238         if (Reflection.isSubclassOf(declaringClass,
239                                     ConstructorAccessorImpl.class)) {
240             return new BootstrapConstructorAccessorImpl(c);
241         }
242 
243         if (noInflation && !c.getDeclaringClass().isHidden()) {
244             return new MethodAccessorGenerator().
245                 generateConstructor(c.getDeclaringClass(),
246                                     c.getParameterTypes(),
247                                     c.getExceptionTypes(),
248                                     c.getModifiers());
249         } else {
250             NativeConstructorAccessorImpl acc = new NativeConstructorAccessorImpl(c);
251             return acc.getParent();
252         }
253     }
254 
255     //--------------------------------------------------------------------------
256     //
257     // Routines used by java.lang
258     //
259     //
260 
261     /** Creates a new java.lang.reflect.Constructor. Access checks as
262         per java.lang.reflect.AccessibleObject are not overridden. */
263     public Constructor<?> newConstructor(Class<?> declaringClass,
264                                          Class<?>[] parameterTypes,
265                                          Class<?>[] checkedExceptions,
266                                          int modifiers,
267                                          int slot,
268                                          String signature,
269                                          byte[] annotations,
270                                          byte[] parameterAnnotations)
271     {
272         return langReflectAccess.newConstructor(declaringClass,
273                                                 parameterTypes,
274                                                 checkedExceptions,
275                                                 modifiers,
276                                                 slot,
277                                                 signature,
278                                                 annotations,
279                                                 parameterAnnotations);
280     }
281 
282     /** Gets the ConstructorAccessor object for a
283         java.lang.reflect.Constructor */
284     public ConstructorAccessor getConstructorAccessor(Constructor<?> c) {
285         return langReflectAccess.getConstructorAccessor(c);
286     }
287 
288     /** Sets the ConstructorAccessor object for a
289         java.lang.reflect.Constructor */
290     public void setConstructorAccessor(Constructor<?> c,
291                                        ConstructorAccessor accessor)
292     {
293         langReflectAccess.setConstructorAccessor(c, accessor);
294     }
295 
296     /** Makes a copy of the passed method. The returned method is a
297         "child" of the passed one; see the comments in Method.java for
298         details. */
299     public Method copyMethod(Method arg) {
300         return langReflectAccess.copyMethod(arg);
301     }
302 
303     /** Makes a copy of the passed method. The returned method is NOT
304      * a "child" but a "sibling" of the Method in arg. Should only be
305      * used on non-root methods. */
306     public Method leafCopyMethod(Method arg) {
307         return langReflectAccess.leafCopyMethod(arg);
308     }
309 
310 
311     /** Makes a copy of the passed field. The returned field is a
312         "child" of the passed one; see the comments in Field.java for
313         details. */
314     public Field copyField(Field arg) {
315         return langReflectAccess.copyField(arg);
316     }
317 
318     /** Makes a copy of the passed constructor. The returned
319         constructor is a "child" of the passed one; see the comments
320         in Constructor.java for details. */
321     public <T> Constructor<T> copyConstructor(Constructor<T> arg) {
322         return langReflectAccess.copyConstructor(arg);
323     }
324 
325     /** Gets the byte[] that encodes TypeAnnotations on an executable.
326      */
327     public byte[] getExecutableTypeAnnotationBytes(Executable ex) {
328         return langReflectAccess.getExecutableTypeAnnotationBytes(ex);
329     }
330 
331     public Class<?>[] getExecutableSharedParameterTypes(Executable ex) {
332         return langReflectAccess.getExecutableSharedParameterTypes(ex);
333     }
334 
335     public <T> T newInstance(Constructor<T> ctor, Object[] args, Class<?> caller)
336         throws IllegalAccessException, InstantiationException, InvocationTargetException
337     {
338         return langReflectAccess.newInstance(ctor, args, caller);
339     }
340 
341     //--------------------------------------------------------------------------
342     //
343     // Routines used by serialization
344     //
345     //
346 
347     public final Constructor<?> newConstructorForExternalization(Class<?> cl) {
348         if (!Externalizable.class.isAssignableFrom(cl)) {
349             return null;
350         }
351         try {
352             Constructor<?> cons = cl.getConstructor();
353             cons.setAccessible(true);
354             return cons;
355         } catch (NoSuchMethodException ex) {
356             return null;
357         }
358     }
359 
360     public final Constructor<?> newConstructorForSerialization(Class<?> cl,
361                                                                Constructor<?> constructorToCall)
362     {
363         if (constructorToCall.getDeclaringClass() == cl) {
364             constructorToCall.setAccessible(true);
365             return constructorToCall;
366         }
367         return generateConstructor(cl, constructorToCall);
368     }
369 
370     /**
371      * Given a class, determines whether its superclass has
372      * any constructors that are accessible from the class.
373      * This is a special purpose method intended to do access
374      * checking for a serializable class and its superclasses
375      * up to, but not including, the first non-serializable
376      * superclass. This also implies that the superclass is
377      * always non-null, because a serializable class must be a
378      * class (not an interface) and Object is not serializable.
379      *
380      * @param cl the class from which access is checked
381      * @return whether the superclass has a constructor accessible from cl
382      */
383     private boolean superHasAccessibleConstructor(Class<?> cl) {
384         Class<?> superCl = cl.getSuperclass();
385         assert Serializable.class.isAssignableFrom(cl);
386         assert superCl != null;
387         if (packageEquals(cl, superCl)) {
388             // accessible if any non-private constructor is found
389             for (Constructor<?> ctor : superCl.getDeclaredConstructors()) {
390                 if ((ctor.getModifiers() & Modifier.PRIVATE) == 0) {
391                     return true;
392                 }
393             }
394             if (Reflection.areNestMates(cl, superCl)) {
395                 return true;
396             }
397             return false;
398         } else {
399             // sanity check to ensure the parent is protected or public
400             if ((superCl.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) == 0) {
401                 return false;
402             }
403             // accessible if any constructor is protected or public
404             for (Constructor<?> ctor : superCl.getDeclaredConstructors()) {
405                 if ((ctor.getModifiers() & (Modifier.PROTECTED | Modifier.PUBLIC)) != 0) {
406                     return true;
407                 }
408             }
409             return false;
410         }
411     }
412 
413     /**
414      * Returns a constructor that allocates an instance of cl and that then initializes
415      * the instance by calling the no-arg constructor of its first non-serializable
416      * superclass. This is specified in the Serialization Specification, section 3.1,
417      * in step 11 of the deserialization process. If cl is not serializable, returns
418      * cl's no-arg constructor. If no accessible constructor is found, or if the
419      * class hierarchy is somehow malformed (e.g., a serializable class has no
420      * superclass), null is returned.
421      *
422      * @param cl the class for which a constructor is to be found
423      * @return the generated constructor, or null if none is available
424      */
425     public final Constructor<?> newConstructorForSerialization(Class<?> cl) {
426         Class<?> initCl = cl;
427         while (Serializable.class.isAssignableFrom(initCl)) {
428             Class<?> prev = initCl;
429             if ((initCl = initCl.getSuperclass()) == null ||
430                 (!disableSerialConstructorChecks && !superHasAccessibleConstructor(prev))) {
431                 return null;
432             }
433         }
434         Constructor<?> constructorToCall;
435         try {
436             constructorToCall = initCl.getDeclaredConstructor();
437             int mods = constructorToCall.getModifiers();
438             if ((mods & Modifier.PRIVATE) != 0 ||
439                     ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
440                             !packageEquals(cl, initCl))) {
441                 return null;
442             }
443         } catch (NoSuchMethodException ex) {
444             return null;
445         }
446         return generateConstructor(cl, constructorToCall);
447     }
448 
449     private final Constructor<?> generateConstructor(Class<?> cl,
450                                                      Constructor<?> constructorToCall) {
451 
452 
453         ConstructorAccessor acc = new MethodAccessorGenerator().
454             generateSerializationConstructor(cl,
455                                              constructorToCall.getParameterTypes(),
456                                              constructorToCall.getExceptionTypes(),
457                                              constructorToCall.getModifiers(),
458                                              constructorToCall.getDeclaringClass());
459         Constructor<?> c = newConstructor(constructorToCall.getDeclaringClass(),
460                                           constructorToCall.getParameterTypes(),
461                                           constructorToCall.getExceptionTypes(),
462                                           constructorToCall.getModifiers(),
463                                           langReflectAccess.
464                                           getConstructorSlot(constructorToCall),
465                                           langReflectAccess.
466                                           getConstructorSignature(constructorToCall),
467                                           langReflectAccess.
468                                           getConstructorAnnotations(constructorToCall),
469                                           langReflectAccess.
470                                           getConstructorParameterAnnotations(constructorToCall));
471         setConstructorAccessor(c, acc);
472         c.setAccessible(true);
473         return c;
474     }
475 
476     public final MethodHandle readObjectForSerialization(Class<?> cl) {
477         return findReadWriteObjectForSerialization(cl, "readObject", ObjectInputStream.class);
478     }
479 
480     public final MethodHandle readObjectNoDataForSerialization(Class<?> cl) {
481         return findReadWriteObjectForSerialization(cl, "readObjectNoData", ObjectInputStream.class);
482     }
483 
484     public final MethodHandle writeObjectForSerialization(Class<?> cl) {
485         return findReadWriteObjectForSerialization(cl, "writeObject", ObjectOutputStream.class);
486     }
487 
488     private final MethodHandle findReadWriteObjectForSerialization(Class<?> cl,
489                                                                    String methodName,
490                                                                    Class<?> streamClass) {
491         if (!Serializable.class.isAssignableFrom(cl)) {
492             return null;
493         }
494 
495         try {
496             Method meth = cl.getDeclaredMethod(methodName, streamClass);
497             int mods = meth.getModifiers();
498             if (meth.getReturnType() != Void.TYPE ||
499                     Modifier.isStatic(mods) ||
500                     !Modifier.isPrivate(mods)) {
501                 return null;
502             }
503             meth.setAccessible(true);
504             return MethodHandles.lookup().unreflect(meth);
505         } catch (NoSuchMethodException ex) {
506             return null;
507         } catch (IllegalAccessException ex1) {
508             throw new InternalError("Error", ex1);
509         }
510     }
511 
512     /**
513      * Returns a MethodHandle for {@code writeReplace} on the serializable class
514      * or null if no match found.
515      * @param cl a serializable class
516      * @returnss the {@code writeReplace} MethodHandle or {@code null} if not found
517      */
518     public final MethodHandle writeReplaceForSerialization(Class<?> cl) {
519         return getReplaceResolveForSerialization(cl, "writeReplace");
520     }
521 
522     /**
523      * Returns a MethodHandle for {@code readResolve} on the serializable class
524      * or null if no match found.
525      * @param cl a serializable class
526      * @returns the {@code writeReplace} MethodHandle or {@code null} if not found
527      */
528     public final MethodHandle readResolveForSerialization(Class<?> cl) {
529         return getReplaceResolveForSerialization(cl, "readResolve");
530     }
531 
532     /**
533      * Lookup readResolve or writeReplace on a class with specified
534      * signature constraints.
535      * @param cl a serializable class
536      * @param methodName the method name to find
537      * @returns a MethodHandle for the method or {@code null} if not found or
538      *       has the wrong signature.
539      */
540     private MethodHandle getReplaceResolveForSerialization(Class<?> cl,
541                                                            String methodName) {
542         if (!Serializable.class.isAssignableFrom(cl)) {
543             return null;
544         }
545 
546         Class<?> defCl = cl;
547         while (defCl != null) {
548             try {
549                 Method m = defCl.getDeclaredMethod(methodName);
550                 if (m.getReturnType() != Object.class) {
551                     return null;
552                 }
553                 int mods = m.getModifiers();
554                 if (Modifier.isStatic(mods) | Modifier.isAbstract(mods)) {
555                     return null;
556                 } else if (Modifier.isPublic(mods) | Modifier.isProtected(mods)) {
557                     // fall through
558                 } else if (Modifier.isPrivate(mods) && (cl != defCl)) {
559                     return null;
560                 } else if (!packageEquals(cl, defCl)) {
561                     return null;
562                 }
563                 try {
564                     // Normal return
565                     m.setAccessible(true);
566                     return MethodHandles.lookup().unreflect(m);
567                 } catch (IllegalAccessException ex0) {
568                     // setAccessible should prevent IAE
569                     throw new InternalError("Error", ex0);
570                 }
571             } catch (NoSuchMethodException ex) {
572                 defCl = defCl.getSuperclass();
573             }
574         }
575         return null;
576     }
577 
578     /**
579      * Returns true if the given class defines a static initializer method,
580      * false otherwise.
581      */
582     public final boolean hasStaticInitializerForSerialization(Class<?> cl) {
583         Method m = hasStaticInitializerMethod;
584         if (m == null) {
585             try {
586                 m = ObjectStreamClass.class.getDeclaredMethod("hasStaticInitializer",
587                         new Class<?>[]{Class.class});
588                 m.setAccessible(true);
589                 hasStaticInitializerMethod = m;
590             } catch (NoSuchMethodException ex) {
591                 throw new InternalError("No such method hasStaticInitializer on "
592                         + ObjectStreamClass.class, ex);
593             }
594         }
595         try {
596             return (Boolean) m.invoke(null, cl);
597         } catch (InvocationTargetException | IllegalAccessException ex) {
598             throw new InternalError("Exception invoking hasStaticInitializer", ex);
599         }
600     }
601 
602     /**
603      * Return the accessible constructor for OptionalDataException signaling eof.
604      * @returns the eof constructor for OptionalDataException
605      */
606     public final Constructor<OptionalDataException> newOptionalDataExceptionForSerialization() {
607         try {
608             Constructor<OptionalDataException> boolCtor =
609                     OptionalDataException.class.getDeclaredConstructor(Boolean.TYPE);
610             boolCtor.setAccessible(true);
611             return boolCtor;
612         } catch (NoSuchMethodException ex) {
613             throw new InternalError("Constructor not found", ex);
614         }
615     }
616 
617     //--------------------------------------------------------------------------
618     //
619     // Internals only below this point
620     //
621 
622     static int inflationThreshold() {
623         return inflationThreshold;
624     }
625 
626     /** We have to defer full initialization of this class until after
627         the static initializer is run since java.lang.reflect.Method's
628         static initializer (more properly, that for
629         java.lang.reflect.AccessibleObject) causes this class's to be
630         run, before the system properties are set up. */
631     private static void checkInitted() {
632         if (initted) return;
633 
634         // Defer initialization until module system is initialized so as
635         // to avoid inflation and spinning bytecode in unnamed modules
636         // during early startup.
637         if (!VM.isModuleSystemInited()) {
638             return;
639         }
640 
641         Properties props = GetPropertyAction.privilegedGetProperties();
642         String val = props.getProperty("sun.reflect.noInflation");
643         if (val != null && val.equals("true")) {
644             noInflation = true;
645         }
646 
647         val = props.getProperty("sun.reflect.inflationThreshold");
648         if (val != null) {
649             try {
650                 inflationThreshold = Integer.parseInt(val);
651             } catch (NumberFormatException e) {
652                 throw new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", e);
653             }
654         }
655 
656         disableSerialConstructorChecks =
657             "true".equals(props.getProperty("jdk.disableSerialConstructorChecks"));
658 
659         initted = true;
660     }
661 
662     /**
663      * Returns true if classes are defined in the classloader and same package, false
664      * otherwise.
665      * @param cl1 a class
666      * @param cl2 another class
667      * @returns true if the two classes are in the same classloader and package
668      */
669     private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
670         assert !cl1.isArray() && !cl2.isArray();
671 
672         if (cl1 == cl2) {
673             return true;
674         }
675 
676         return cl1.getClassLoader() == cl2.getClassLoader() &&
677                 cl1.getPackageName() == cl2.getPackageName();
678     }
679 
680 }