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