1 /*
2  * Copyright 2014 - 2020 Rafael Winterhalter
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package net.bytebuddy.dynamic.loading;
17
18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import net.bytebuddy.ByteBuddy;
20 import net.bytebuddy.asm.MemberRemoval;
21 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
22 import net.bytebuddy.description.modifier.Visibility;
23 import net.bytebuddy.description.type.PackageDescription;
24 import net.bytebuddy.description.type.TypeDescription;
25 import net.bytebuddy.dynamic.DynamicType;
26 import net.bytebuddy.dynamic.scaffold.TypeValidation;
27 import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
28 import net.bytebuddy.implementation.FixedValue;
29 import net.bytebuddy.implementation.MethodCall;
30 import net.bytebuddy.utility.JavaModule;
31 import net.bytebuddy.utility.JavaType;
32 import net.bytebuddy.utility.RandomString;
33
34 import java.io.File;
35 import java.io.FileOutputStream;
36 import java.io.IOException;
37 import java.lang.instrument.Instrumentation;
38 import java.lang.reflect.*;
39 import java.net.URL;
40 import java.security.AccessController;
41 import java.security.Permission;
42 import java.security.PrivilegedAction;
43 import java.security.ProtectionDomain;
44 import java.util.*;
45 import java.util.jar.JarEntry;
46 import java.util.jar.JarFile;
47 import java.util.jar.JarOutputStream;
48
49 import static net.bytebuddy.matcher.ElementMatchers.any;
50 import static net.bytebuddy.matcher.ElementMatchers.named;
51
52 /**
53  * <p>
54  * A class injector is capable of injecting classes into a {@link java.lang.ClassLoader} without
55  * requiring the class loader to being able to explicitly look up these classes.
56  * </p>
57  * <p>
58  * <b>Important</b>: Byte Buddy does not supply privileges when injecting code. When using a {@link SecurityManager},
59  * the user of this injector is responsible for providing access to non-public properties.
60  * </p>
61  */

62 public interface ClassInjector {
63
64     /**
65      * A permission for the {@code suppressAccessChecks} permission.
66      */

67     Permission SUPPRESS_ACCESS_CHECKS = new ReflectPermission("suppressAccessChecks");
68
69     /**
70      * Determines the default behavior for type injections when a type is already loaded.
71      */

72     boolean ALLOW_EXISTING_TYPES = false;
73
74     /**
75      * Indicates if this class injector is available on the current VM.
76      *
77      * @return {@code trueif this injector is available on the current VM.
78      */

79     boolean isAlive();
80
81     /**
82      * Injects the given types into the represented class loader.
83      *
84      * @param types The types to load via injection.
85      * @return The loaded types that were passed as arguments.
86      */

87     Map<TypeDescription, Class<?>> inject(Map<? extends TypeDescription, byte[]> types);
88
89     /**
90      * Injects the given types into the represented class loader using a mapping from name to binary representation.
91      *
92      * @param types The types to load via injection.
93      * @return The loaded types that were passed as arguments.
94      */

95     Map<String, Class<?>> injectRaw(Map<? extends String, byte[]> types);
96
97     /**
98      * An abstract base implementation of a class injector.
99      */

100     abstract class AbstractBase implements ClassInjector {
101
102         /**
103          * {@inheritDoc}
104          */

105         public Map<TypeDescription, Class<?>> inject(Map<? extends TypeDescription, byte[]> types) {
106             Map<String, byte[]> binaryRepresentations = new LinkedHashMap<String, byte[]>();
107             for (Map.Entry<? extends TypeDescription, byte[]> entry : types.entrySet()) {
108                 binaryRepresentations.put(entry.getKey().getName(), entry.getValue());
109             }
110             Map<String, Class<?>> loadedTypes = injectRaw(binaryRepresentations);
111             Map<TypeDescription, Class<?>> result = new LinkedHashMap<TypeDescription, Class<?>>();
112             for (TypeDescription typeDescription : types.keySet()) {
113                 result.put(typeDescription, loadedTypes.get(typeDescription.getName()));
114             }
115             return result;
116         }
117     }
118
119     /**
120      * A class injector that uses reflective method calls.
121      */

122     @HashCodeAndEqualsPlugin.Enhance
123     class UsingReflection extends AbstractBase {
124
125         /**
126          * The dispatcher to use for accessing a class loader via reflection.
127          */

128         private static final Dispatcher.Initializable DISPATCHER = AccessController.doPrivileged(Dispatcher.CreationAction.INSTANCE);
129
130         /**
131          * The class loader into which the classes are to be injected.
132          */

133         private final ClassLoader classLoader;
134
135         /**
136          * The protection domain that is used when loading classes.
137          */

138         @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
139         private final ProtectionDomain protectionDomain;
140
141         /**
142          * The package definer to be queried for package definitions.
143          */

144         private final PackageDefinitionStrategy packageDefinitionStrategy;
145
146         /**
147          * Determines if an exception should be thrown when attempting to load a type that already exists.
148          */

149         private final boolean forbidExisting;
150
151         /**
152          * Creates a new injector for the given {@link java.lang.ClassLoader} and a default {@link java.security.ProtectionDomain} and a
153          * trivial {@link PackageDefinitionStrategy} which does not trigger an error when discovering existent classes.
154          *
155          * @param classLoader The {@link java.lang.ClassLoader} into which new class definitions are to be injected. Must not be the bootstrap loader.
156          */

157         public UsingReflection(ClassLoader classLoader) {
158             this(classLoader, ClassLoadingStrategy.NO_PROTECTION_DOMAIN);
159         }
160
161         /**
162          * Creates a new injector for the given {@link java.lang.ClassLoader} and a default {@link PackageDefinitionStrategy} where the
163          * injection of existent classes does not trigger an error.
164          *
165          * @param classLoader      The {@link java.lang.ClassLoader} into which new class definitions are to be injected. Must not be the bootstrap loader.
166          * @param protectionDomain The protection domain to apply during class definition.
167          */

168         public UsingReflection(ClassLoader classLoader, ProtectionDomain protectionDomain) {
169             this(classLoader,
170                     protectionDomain,
171                     PackageDefinitionStrategy.Trivial.INSTANCE,
172                     ALLOW_EXISTING_TYPES);
173         }
174
175         /**
176          * Creates a new injector for the given {@link java.lang.ClassLoader} and {@link java.security.ProtectionDomain}.
177          *
178          * @param classLoader               The {@link java.lang.ClassLoader} into which new class definitions are to be injected.Must  not be the bootstrap loader.
179          * @param protectionDomain          The protection domain to apply during class definition.
180          * @param packageDefinitionStrategy The package definer to be queried for package definitions.
181          * @param forbidExisting            Determines if an exception should be thrown when attempting to load a type that already exists.
182          */

183         public UsingReflection(ClassLoader classLoader,
184                                ProtectionDomain protectionDomain,
185                                PackageDefinitionStrategy packageDefinitionStrategy,
186                                boolean forbidExisting) {
187             if (classLoader == null) {
188                 throw new IllegalArgumentException("Cannot inject classes into the bootstrap class loader");
189             }
190             this.classLoader = classLoader;
191             this.protectionDomain = protectionDomain;
192             this.packageDefinitionStrategy = packageDefinitionStrategy;
193             this.forbidExisting = forbidExisting;
194         }
195
196         /**
197          * {@inheritDoc}
198          */

199         public boolean isAlive() {
200             return isAvailable();
201         }
202
203         /**
204          * {@inheritDoc}
205          */

206         public Map<String, Class<?>> injectRaw(Map<? extends String, byte[]> types) {
207             Dispatcher dispatcher = DISPATCHER.initialize();
208             Map<String, Class<?>> result = new HashMap<String, Class<?>>();
209             for (Map.Entry<? extends String, byte[]> entry : types.entrySet()) {
210                 synchronized (dispatcher.getClassLoadingLock(classLoader, entry.getKey())) {
211                     Class<?> type = dispatcher.findClass(classLoader, entry.getKey());
212                     if (type == null) {
213                         int packageIndex = entry.getKey().lastIndexOf('.');
214                         if (packageIndex != -1) {
215                             String packageName = entry.getKey().substring(0, packageIndex);
216                             PackageDefinitionStrategy.Definition definition = packageDefinitionStrategy.define(classLoader, packageName, entry.getKey());
217                             if (definition.isDefined()) {
218                                 Package definedPackage = dispatcher.getPackage(classLoader, packageName);
219                                 if (definedPackage == null) {
220                                     dispatcher.definePackage(classLoader,
221                                             packageName,
222                                             definition.getSpecificationTitle(),
223                                             definition.getSpecificationVersion(),
224                                             definition.getSpecificationVendor(),
225                                             definition.getImplementationTitle(),
226                                             definition.getImplementationVersion(),
227                                             definition.getImplementationVendor(),
228                                             definition.getSealBase());
229                                 } else if (!definition.isCompatibleTo(definedPackage)) {
230                                     throw new SecurityException("Sealing violation for package " + packageName);
231                                 }
232                             }
233                         }
234                         type = dispatcher.defineClass(classLoader, entry.getKey(), entry.getValue(), protectionDomain);
235                     } else if (forbidExisting) {
236                         throw new IllegalStateException("Cannot inject already loaded type: " + type);
237                     }
238                     result.put(entry.getKey(), type);
239                 }
240             }
241             return result;
242         }
243
244         /**
245          * Indicates if this class injection is available on the current VM.
246          *
247          * @return {@code trueif this class injection is available.
248          */

249         public static boolean isAvailable() {
250             return DISPATCHER.isAvailable();
251         }
252
253         /**
254          * Creates a class injector for the system class loader.
255          *
256          * @return A class injector for the system class loader.
257          */

258         public static ClassInjector ofSystemClassLoader() {
259             return new UsingReflection(ClassLoader.getSystemClassLoader());
260         }
261
262         /**
263          * A dispatcher for accessing a {@link ClassLoader} reflectively.
264          */

265         protected interface Dispatcher {
266
267             /**
268              * Indicates a class that is currently not defined.
269              */

270             Class<?> UNDEFINED = null;
271
272             /**
273              * Returns the lock for loading the specified class.
274              *
275              * @param classLoader the class loader to inject the class into.
276              * @param name        The name of the class.
277              * @return The lock for loading this class.
278              */

279             Object getClassLoadingLock(ClassLoader classLoader, String name);
280
281             /**
282              * Looks up a class from the given class loader.
283              *
284              * @param classLoader The class loader for which a class should be located.
285              * @param name        The binary name of the class that should be located.
286              * @return The class for the binary name or {@code nullif no such class is defined for the provided class loader.
287              */

288             Class<?> findClass(ClassLoader classLoader, String name);
289
290             /**
291              * Defines a class for the given class loader.
292              *
293              * @param classLoader          The class loader for which a new class should be defined.
294              * @param name                 The binary name of the class that should be defined.
295              * @param binaryRepresentation The binary representation of the class.
296              * @param protectionDomain     The protection domain for the defined class.
297              * @return The defined, loaded class.
298              */

299             Class<?> defineClass(ClassLoader classLoader, String name, byte[] binaryRepresentation, ProtectionDomain protectionDomain);
300
301             /**
302              * Looks up a package from a class loader.
303              *
304              * @param classLoader The class loader to query.
305              * @param name        The binary name of the package.
306              * @return The package for the given name as defined by the provided class loader or {@code nullif no such package exists.
307              */

308             Package getPackage(ClassLoader classLoader, String name);
309
310             /**
311              * Defines a package for the given class loader.
312              *
313              * @param classLoader           The class loader for which a package is to be defined.
314              * @param name                  The binary name of the package.
315              * @param specificationTitle    The specification title of the package or {@code nullif no specification title exists.
316              * @param specificationVersion  The specification version of the package or {@code nullif no specification version exists.
317              * @param specificationVendor   The specification vendor of the package or {@code nullif no specification vendor exists.
318              * @param implementationTitle   The implementation title of the package or {@code nullif no implementation title exists.
319              * @param implementationVersion The implementation version of the package or {@code nullif no implementation version exists.
320              * @param implementationVendor  The implementation vendor of the package or {@code nullif no implementation vendor exists.
321              * @param sealBase              The seal base URL or {@code nullif the package should not be sealed.
322              * @return The defined package.
323              */

324             Package definePackage(ClassLoader classLoader,
325                                   String name,
326                                   String specificationTitle,
327                                   String specificationVersion,
328                                   String specificationVendor,
329                                   String implementationTitle,
330                                   String implementationVersion,
331                                   String implementationVendor,
332                                   URL sealBase);
333
334             /**
335              * Initializes a dispatcher to make non-accessible APIs accessible.
336              */

337             interface Initializable {
338
339                 /**
340                  * Indicates if this dispatcher is available.
341                  *
342                  * @return {@code trueif this dispatcher is available.
343                  */

344                 boolean isAvailable();
345
346                 /**
347                  * Initializes this dispatcher.
348                  *
349                  * @return The initialized dispatcher.
350                  */

351                 Dispatcher initialize();
352
353                 /**
354                  * Represents an unsuccessfully loaded method lookup.
355                  */

356                 @HashCodeAndEqualsPlugin.Enhance
357                 class Unavailable implements Dispatcher, Initializable {
358
359                     /**
360                      * The reason why this dispatcher is not available.
361                      */

362                     private final String message;
363
364                     /**
365                      * Creates a new faulty reflection store.
366                      *
367                      * @param message The reason why this dispatcher is not available.
368                      */

369                     protected Unavailable(String message) {
370                         this.message = message;
371                     }
372
373                     /**
374                      * {@inheritDoc}
375                      */

376                     public boolean isAvailable() {
377                         return false;
378                     }
379
380                     /**
381                      * {@inheritDoc}
382                      */

383                     public Dispatcher initialize() {
384                         return this;
385                     }
386
387                     /**
388                      * {@inheritDoc}
389                      */

390                     public Object getClassLoadingLock(ClassLoader classLoader, String name) {
391                         return classLoader;
392                     }
393
394                     /**
395                      * {@inheritDoc}
396                      */

397                     public Class<?> findClass(ClassLoader classLoader, String name) {
398                         try {
399                             return classLoader.loadClass(name);
400                         } catch (ClassNotFoundException ignored) {
401                             return UNDEFINED;
402                         }
403                     }
404
405                     /**
406                      * {@inheritDoc}
407                      */

408                     public Class<?> defineClass(ClassLoader classLoader, String name, byte[] binaryRepresentation, ProtectionDomain protectionDomain) {
409                         throw new UnsupportedOperationException("Cannot define class using reflection: " + message);
410                     }
411
412                     /**
413                      * {@inheritDoc}
414                      */

415                     public Package getPackage(ClassLoader classLoader, String name) {
416                         throw new UnsupportedOperationException("Cannot get package using reflection: " + message);
417                     }
418
419                     /**
420                      * {@inheritDoc}
421                      */

422                     public Package definePackage(ClassLoader classLoader,
423                                                  String name,
424                                                  String specificationTitle,
425                                                  String specificationVersion,
426                                                  String specificationVendor,
427                                                  String implementationTitle,
428                                                  String implementationVersion,
429                                                  String implementationVendor,
430                                                  URL sealBase) {
431                         throw new UnsupportedOperationException("Cannot define package using injection: " + message);
432                     }
433                 }
434             }
435
436             /**
437              * A creation action for a dispatcher.
438              */

439             enum CreationAction implements PrivilegedAction<Initializable> {
440
441                 /**
442                  * The singleton instance.
443                  */

444                 INSTANCE;
445
446                 /**
447                  * {@inheritDoc}
448                  */

449                 @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback")
450                 public Initializable run() {
451                     try {
452                         if (JavaModule.isSupported()) {
453                             return UsingUnsafe.isAvailable()
454                                     ? UsingUnsafeInjection.make()
455                                     : UsingUnsafeOverride.make();
456                         } else {
457                             return Direct.make();
458                         }
459                     } catch (InvocationTargetException exception) {
460                         return new Initializable.Unavailable(exception.getCause().getMessage());
461                     } catch (Exception exception) {
462                         return new Initializable.Unavailable(exception.getMessage());
463                     }
464                 }
465             }
466
467             /**
468              * A class injection dispatcher that is using reflection on the {@link ClassLoader} methods.
469              */

470             @HashCodeAndEqualsPlugin.Enhance
471             abstract class Direct implements Dispatcher, Initializable {
472
473                 /**
474                  * An instance of {@link ClassLoader#findLoadedClass(String)}.
475                  */

476                 protected final Method findLoadedClass;
477
478                 /**
479                  * An instance of {@link ClassLoader#defineClass(String, byte[], intint, ProtectionDomain)}.
480                  */

481                 protected final Method defineClass;
482
483                 /**
484                  * An instance of {@link ClassLoader#getPackage(String)} or {@code ClassLoader#getDefinedPackage(String)}.
485                  */

486                 protected final Method getPackage;
487
488                 /**
489                  * An instance of {@link ClassLoader#definePackage(String, String, String, String, String, String, String, URL)}.
490                  */

491                 protected final Method definePackage;
492
493                 /**
494                  * Creates a new direct injection dispatcher.
495                  *
496                  * @param findLoadedClass An instance of {@link ClassLoader#findLoadedClass(String)}.
497                  * @param defineClass     An instance of {@link ClassLoader#defineClass(String, byte[], intint, ProtectionDomain)}.
498                  * @param getPackage      An instance of {@link ClassLoader#getPackage(String)} or {@code ClassLoader#getDefinedPackage(String)}.
499                  * @param definePackage   An instance of {@link ClassLoader#definePackage(String, String, String, String, String, String, String, URL)}.
500                  */

501                 protected Direct(Method findLoadedClass,
502                                  Method defineClass,
503                                  Method getPackage,
504                                  Method definePackage) {
505                     this.findLoadedClass = findLoadedClass;
506                     this.defineClass = defineClass;
507                     this.getPackage = getPackage;
508                     this.definePackage = definePackage;
509                 }
510
511                 /**
512                  * Creates a direct dispatcher.
513                  *
514                  * @return A direct dispatcher for class injection.
515                  * @throws Exception If the creation is impossible.
516                  */

517                 @SuppressFBWarnings(value = "DP_DO_INSIDE_DO_PRIVILEGED", justification = "Privilege is explicit caller responsibility")
518                 protected static Initializable make() throws Exception {
519                     Method getPackage;
520                     if (JavaModule.isSupported()) { // Avoid accidental lookup of method with same name in Java 8 J9 VM.
521                         try {
522                             getPackage = ClassLoader.class.getMethod("getDefinedPackage", String.class);
523                         } catch (NoSuchMethodException ignored) {
524                             getPackage = ClassLoader.class.getDeclaredMethod("getPackage", String.class);
525                             getPackage.setAccessible(true);
526                         }
527                     } else {
528                         getPackage = ClassLoader.class.getDeclaredMethod("getPackage", String.class);
529                         getPackage.setAccessible(true);
530                     }
531                     Method findLoadedClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
532                     findLoadedClass.setAccessible(true);
533                     Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass",
534                             String.class,
535                             byte[].class,
536                             int.class,
537                             int.class,
538                             ProtectionDomain.class);
539                     defineClass.setAccessible(true);
540                     Method definePackage = ClassLoader.class.getDeclaredMethod("definePackage",
541                             String.class,
542                             String.class,
543                             String.class,
544                             String.class,
545                             String.class,
546                             String.class,
547                             String.class,
548                             URL.class);
549                     definePackage.setAccessible(true);
550                     try {
551                         Method getClassLoadingLock = ClassLoader.class.getDeclaredMethod("getClassLoadingLock", String.class);
552                         getClassLoadingLock.setAccessible(true);
553                         return new ForJava7CapableVm(findLoadedClass,
554                                 defineClass,
555                                 getPackage,
556                                 definePackage,
557                                 getClassLoadingLock);
558                     } catch (NoSuchMethodException ignored) {
559                         return new ForLegacyVm(findLoadedClass, defineClass, getPackage, definePackage);
560                     }
561                 }
562
563                 /**
564                  * {@inheritDoc}
565                  */

566                 public boolean isAvailable() {
567                     return true;
568                 }
569
570                 /**
571                  * {@inheritDoc}
572                  */

573                 public Dispatcher initialize() {
574                     SecurityManager securityManager = System.getSecurityManager();
575                     if (securityManager != null) {
576                         try {
577                             securityManager.checkPermission(SUPPRESS_ACCESS_CHECKS);
578                         } catch (Exception exception) {
579                             return new Dispatcher.Unavailable(exception.getMessage());
580                         }
581                     }
582                     return this;
583                 }
584
585                 /**
586                  * {@inheritDoc}
587                  */

588                 public Class<?> findClass(ClassLoader classLoader, String name) {
589                     try {
590                         return (Class<?>) findLoadedClass.invoke(classLoader, name);
591                     } catch (IllegalAccessException exception) {
592                         throw new IllegalStateException("Could not access java.lang.ClassLoader#findClass", exception);
593                     } catch (InvocationTargetException exception) {
594                         throw new IllegalStateException("Error invoking java.lang.ClassLoader#findClass", exception.getCause());
595                     }
596                 }
597
598                 /**
599                  * {@inheritDoc}
600                  */

601                 public Class<?> defineClass(ClassLoader classLoader, String name, byte[] binaryRepresentation, ProtectionDomain protectionDomain) {
602                     try {
603                         return (Class<?>) defineClass.invoke(classLoader, name, binaryRepresentation, 0, binaryRepresentation.length, protectionDomain);
604                     } catch (IllegalAccessException exception) {
605                         throw new IllegalStateException("Could not access java.lang.ClassLoader#defineClass", exception);
606                     } catch (InvocationTargetException exception) {
607                         throw new IllegalStateException("Error invoking java.lang.ClassLoader#defineClass", exception.getCause());
608                     }
609                 }
610
611                 /**
612                  * {@inheritDoc}
613                  */

614                 public Package getPackage(ClassLoader classLoader, String name) {
615                     try {
616                         return (Package) getPackage.invoke(classLoader, name);
617                     } catch (IllegalAccessException exception) {
618                         throw new IllegalStateException("Could not access java.lang.ClassLoader#getPackage", exception);
619                     } catch (InvocationTargetException exception) {
620                         throw new IllegalStateException("Error invoking java.lang.ClassLoader#getPackage", exception.getCause());
621                     }
622                 }
623
624                 /**
625                  * {@inheritDoc}
626                  */

627                 public Package definePackage(ClassLoader classLoader,
628                                              String name,
629                                              String specificationTitle,
630                                              String specificationVersion,
631                                              String specificationVendor,
632                                              String implementationTitle,
633                                              String implementationVersion,
634                                              String implementationVendor,
635                                              URL sealBase) {
636                     try {
637                         return (Package) definePackage.invoke(classLoader,
638                                 name,
639                                 specificationTitle,
640                                 specificationVersion,
641                                 specificationVendor,
642                                 implementationTitle,
643                                 implementationVersion,
644                                 implementationVendor,
645                                 sealBase);
646                     } catch (IllegalAccessException exception) {
647                         throw new IllegalStateException("Could not access java.lang.ClassLoader#definePackage", exception);
648                     } catch (InvocationTargetException exception) {
649                         throw new IllegalStateException("Error invoking java.lang.ClassLoader#definePackage", exception.getCause());
650                     }
651                 }
652
653                 /**
654                  * A resolved class dispatcher for a class injector on a VM running at least Java 7.
655                  */

656                 @HashCodeAndEqualsPlugin.Enhance
657                 protected static class ForJava7CapableVm extends Direct {
658
659                     /**
660                      * An instance of {@code ClassLoader#getClassLoadingLock(String)}.
661                      */

662                     private final Method getClassLoadingLock;
663
664                     /**
665                      * Creates a new resolved reflection store for a VM running at least Java 7.
666                      *
667                      * @param getClassLoadingLock An instance of {@code ClassLoader#getClassLoadingLock(String)}.
668                      * @param findLoadedClass     An instance of {@link ClassLoader#findLoadedClass(String)}.
669                      * @param defineClass         An instance of {@link ClassLoader#defineClass(String, byte[], intint, ProtectionDomain)}.
670                      * @param getPackage          An instance of {@link ClassLoader#getPackage(String)} or {@code ClassLoader#getDefinedPackage(String)}.
671                      * @param definePackage       An instance of {@link ClassLoader#definePackage(String, String, String, String, String, String, String, URL)}.
672                      */

673                     protected ForJava7CapableVm(Method findLoadedClass,
674                                                 Method defineClass,
675                                                 Method getPackage,
676                                                 Method definePackage,
677                                                 Method getClassLoadingLock) {
678                         super(findLoadedClass, defineClass, getPackage, definePackage);
679                         this.getClassLoadingLock = getClassLoadingLock;
680                     }
681
682                     /**
683                      * {@inheritDoc}
684                      */

685                     public Object getClassLoadingLock(ClassLoader classLoader, String name) {
686                         try {
687                             return getClassLoadingLock.invoke(classLoader, name);
688                         } catch (IllegalAccessException exception) {
689                             throw new IllegalStateException("Could not access java.lang.ClassLoader#getClassLoadingLock", exception);
690                         } catch (InvocationTargetException exception) {
691                             throw new IllegalStateException("Error invoking java.lang.ClassLoader#getClassLoadingLock", exception.getCause());
692                         }
693                     }
694                 }
695
696                 /**
697                  * A resolved class dispatcher for a class injector prior to Java 7.
698                  */

699                 protected static class ForLegacyVm extends Direct {
700
701                     /**
702                      * Creates a new resolved reflection store for a VM prior to Java 8.
703                      *
704                      * @param findLoadedClass An instance of {@link ClassLoader#findLoadedClass(String)}.
705                      * @param defineClass     An instance of {@link ClassLoader#defineClass(String, byte[], intint, ProtectionDomain)}.
706                      * @param getPackage      An instance of {@link ClassLoader#getPackage(String)} or {@code ClassLoader#getDefinedPackage(String)}.
707                      * @param definePackage   An instance of {@link ClassLoader#definePackage(String, String, String, String, String, String, String, URL)}.
708                      */

709                     protected ForLegacyVm(Method findLoadedClass,
710                                           Method defineClass,
711                                           Method getPackage,
712                                           Method definePackage) {
713                         super(findLoadedClass, defineClass, getPackage, definePackage);
714                     }
715
716                     /**
717                      * {@inheritDoc}
718                      */

719                     public Object getClassLoadingLock(ClassLoader classLoader, String name) {
720                         return classLoader;
721                     }
722                 }
723             }
724
725             /**
726              * An indirect dispatcher that uses a redirection accessor class that was injected into the bootstrap class loader.
727              */

728             @HashCodeAndEqualsPlugin.Enhance
729             class UsingUnsafeInjection implements Dispatcher, Initializable {
730
731                 /**
732                  * An instance of the accessor class that is required for using it's intentionally non-static methods.
733                  */

734                 private final Object accessor;
735
736                 /**
737                  * The accessor method for using {@link ClassLoader#findLoadedClass(String)}.
738                  */

739                 private final Method findLoadedClass;
740
741                 /**
742                  * The accessor method for using {@link ClassLoader#defineClass(String, byte[], intint, ProtectionDomain)}.
743                  */

744                 private final Method defineClass;
745
746                 /**
747                  * The accessor method for using {@link ClassLoader#getPackage(String)} or {@code ClassLoader#getDefinedPackage(String)}.
748                  */

749                 private final Method getPackage;
750
751                 /**
752                  * The accessor method for using {@link ClassLoader#definePackage(String, String, String, String, String, String, String, URL)}.
753                  */

754                 private final Method definePackage;
755
756                 /**
757                  * The accessor method for using {@code ClassLoader#getClassLoadingLock(String)} or returning the supplied {@link ClassLoader}
758                  * if this method does not exist on the current VM.
759                  */

760                 private final Method getClassLoadingLock;
761
762                 /**
763                  * Creates a new class loading injection dispatcher using an unsafe injected dispatcher.
764                  *
765                  * @param accessor            An instance of the accessor class that is required for using it's intentionally non-static methods.
766                  * @param findLoadedClass     An instance of {@link ClassLoader#findLoadedClass(String)}.
767                  * @param defineClass         An instance of {@link ClassLoader#defineClass(String, byte[], intint, ProtectionDomain)}.
768                  * @param getPackage          An instance of {@link ClassLoader#getPackage(String)} or {@code ClassLoader#getDefinedPackage(String)}.
769                  * @param definePackage       An instance of {@link ClassLoader#definePackage(String, String, String, String, String, String, String, URL)}.
770                  * @param getClassLoadingLock The accessor method for using {@code ClassLoader#getClassLoadingLock(String)} or returning the
771                  *                            supplied {@link ClassLoader} if this method does not exist on the current VM.
772                  */

773                 protected UsingUnsafeInjection(Object accessor,
774                                                Method findLoadedClass,
775                                                Method defineClass,
776                                                Method getPackage,
777                                                Method definePackage,
778                                                Method getClassLoadingLock) {
779                     this.accessor = accessor;
780                     this.findLoadedClass = findLoadedClass;
781                     this.defineClass = defineClass;
782                     this.getPackage = getPackage;
783                     this.definePackage = definePackage;
784                     this.getClassLoadingLock = getClassLoadingLock;
785                 }
786
787                 /**
788                  * Creates an indirect dispatcher.
789                  *
790                  * @return An indirect dispatcher for class creation.
791                  * @throws Exception If the dispatcher cannot be created.
792                  */

793                 @SuppressFBWarnings(value = "DP_DO_INSIDE_DO_PRIVILEGED", justification = "Privilege is explicit caller responsibility")
794                 protected static Initializable make() throws Exception {
795                     if (Boolean.getBoolean(UsingUnsafe.SAFE_PROPERTY)) {
796                         return new Initializable.Unavailable("Use of Unsafe was disabled by system property");
797                     }
798                     Class<?> unsafe = Class.forName("sun.misc.Unsafe");
799                     Field theUnsafe = unsafe.getDeclaredField("theUnsafe");
800                     theUnsafe.setAccessible(true);
801                     Object unsafeInstance = theUnsafe.get(null);
802                     Method getPackage;
803                     if (JavaModule.isSupported()) { // Avoid accidental lookup of method with same name in Java 8 J9 VM.
804                         try {
805                             getPackage = ClassLoader.class.getDeclaredMethod("getDefinedPackage", String.class);
806                         } catch (NoSuchMethodException ignored) {
807                             getPackage = ClassLoader.class.getDeclaredMethod("getPackage", String.class);
808                         }
809                     } else {
810                         getPackage = ClassLoader.class.getDeclaredMethod("getPackage", String.class);
811                     }
812                     getPackage.setAccessible(true);
813                     DynamicType.Builder<?> builder = new ByteBuddy()
814                             .with(TypeValidation.DISABLED)
815                             .subclass(Object.class, ConstructorStrategy.Default.NO_CONSTRUCTORS)
816                             .name(ClassLoader.class.getName() + "$ByteBuddyAccessor$" + RandomString.make())
817                             .defineMethod("findLoadedClass", Class.class, Visibility.PUBLIC)
818                             .withParameters(ClassLoader.class, String.class)
819                             .intercept(MethodCall.invoke(ClassLoader.class
820                                     .getDeclaredMethod("findLoadedClass", String.class))
821                                     .onArgument(0)
822                                     .withArgument(1))
823                             .defineMethod("defineClass", Class.class, Visibility.PUBLIC)
824                             .withParameters(ClassLoader.class, String.classbyte[].classint.classint.class,
825                                     ProtectionDomain.class)
826                             .intercept(MethodCall.invoke(ClassLoader.class
827                                     .getDeclaredMethod("defineClass", String.classbyte[].classint.classint.class, ProtectionDomain.class))
828                                     .onArgument(0)
829                                     .withArgument(1, 2, 3, 4, 5))
830                             .defineMethod("getPackage", Package.class, Visibility.PUBLIC)
831                             .withParameters(ClassLoader.class, String.class)
832                             .intercept(MethodCall.invoke(getPackage)
833                                     .onArgument(0)
834                                     .withArgument(1))
835                             .defineMethod("definePackage", Package.class, Visibility.PUBLIC)
836                             .withParameters(ClassLoader.class, String.class, String.class, String.class, String.class,
837                                     String.class, String.class, String.class, URL.class)
838                             .intercept(MethodCall.invoke(ClassLoader.class
839                                     .getDeclaredMethod("definePackage", String.class, String.class, String.class, String.class, String.class, String.class, String.class, URL.class))
840                                     .onArgument(0)
841                                     .withArgument(1, 2, 3, 4, 5, 6, 7, 8));
842                     try {
843                         builder = builder.defineMethod("getClassLoadingLock", Object.class, Visibility.PUBLIC)
844                                 .withParameters(ClassLoader.class, String.class)
845                                 .intercept(MethodCall.invoke(ClassLoader.class.getDeclaredMethod("getClassLoadingLock", String.class))
846                                         .onArgument(0)
847                                         .withArgument(1));
848                     } catch (NoSuchMethodException ignored) {
849                         builder = builder.defineMethod("getClassLoadingLock", Object.class, Visibility.PUBLIC)
850                                 .withParameters(ClassLoader.class, String.class)
851                                 .intercept(FixedValue.argument(0));
852                     }
853                     Class<?> type = builder.make()
854                             .load(ClassLoadingStrategy.BOOTSTRAP_LOADER, new ClassLoadingStrategy.ForUnsafeInjection())
855                             .getLoaded();
856                     return new UsingUnsafeInjection(
857                             unsafe.getMethod("allocateInstance", Class.class).invoke(unsafeInstance, type),
858                             type.getMethod("findLoadedClass", ClassLoader.class, String.class),
859                             type.getMethod("defineClass", ClassLoader.class, String.classbyte[].classint.classint.class, ProtectionDomain.class),
860                             type.getMethod("getPackage", ClassLoader.class, String.class),
861                             type.getMethod("definePackage", ClassLoader.class, String.class, String.class, String.class, String.class, String.class, String.class, String.class, URL.class),
862                             type.getMethod("getClassLoadingLock", ClassLoader.class, String.class));
863                 }
864
865                 /**
866                  * {@inheritDoc}
867                  */

868                 public boolean isAvailable() {
869                     return true;
870                 }
871
872                 /**
873                  * {@inheritDoc}
874                  */

875                 public Dispatcher initialize() {
876                     SecurityManager securityManager = System.getSecurityManager();
877                     if (securityManager != null) {
878                         try {
879                             securityManager.checkPermission(SUPPRESS_ACCESS_CHECKS);
880                         } catch (Exception exception) {
881                             return new Dispatcher.Unavailable(exception.getMessage());
882                         }
883                     }
884                     return this;
885                 }
886
887                 /**
888                  * {@inheritDoc}
889                  */

890                 public Object getClassLoadingLock(ClassLoader classLoader, String name) {
891                     try {
892                         return getClassLoadingLock.invoke(accessor, classLoader, name);
893                     } catch (IllegalAccessException exception) {
894                         throw new IllegalStateException("Could not access (accessor)::getClassLoadingLock", exception);
895                     } catch (InvocationTargetException exception) {
896                         throw new IllegalStateException("Error invoking (accessor)::getClassLoadingLock", exception.getCause());
897                     }
898                 }
899
900                 /**
901                  * {@inheritDoc}
902                  */

903                 public Class<?> findClass(ClassLoader classLoader, String name) {
904                     try {
905                         return (Class<?>) findLoadedClass.invoke(accessor, classLoader, name);
906                     } catch (IllegalAccessException exception) {
907                         throw new IllegalStateException("Could not access (accessor)::findLoadedClass", exception);
908                     } catch (InvocationTargetException exception) {
909                         throw new IllegalStateException("Error invoking (accessor)::findLoadedClass", exception.getCause());
910                     }
911                 }
912
913                 /**
914                  * {@inheritDoc}
915                  */

916                 public Class<?> defineClass(ClassLoader classLoader, String name, byte[] binaryRepresentation, ProtectionDomain protectionDomain) {
917                     try {
918                         return (Class<?>) defineClass.invoke(accessor, classLoader, name, binaryRepresentation, 0, binaryRepresentation.length, protectionDomain);
919                     } catch (IllegalAccessException exception) {
920                         throw new IllegalStateException("Could not access (accessor)::defineClass", exception);
921                     } catch (InvocationTargetException exception) {
922                         throw new IllegalStateException("Error invoking (accessor)::defineClass", exception.getCause());
923                     }
924                 }
925
926                 /**
927                  * {@inheritDoc}
928                  */

929                 public Package getPackage(ClassLoader classLoader, String name) {
930                     try {
931                         return (Package) getPackage.invoke(accessor, classLoader, name);
932                     } catch (IllegalAccessException exception) {
933                         throw new IllegalStateException("Could not access (accessor)::getPackage", exception);
934                     } catch (InvocationTargetException exception) {
935                         throw new IllegalStateException("Error invoking (accessor)::getPackage", exception.getCause());
936                     }
937                 }
938
939                 /**
940                  * {@inheritDoc}
941                  */

942                 public Package definePackage(ClassLoader classLoader,
943                                              String name,
944                                              String specificationTitle,
945                                              String specificationVersion,
946                                              String specificationVendor,
947                                              String implementationTitle,
948                                              String implementationVersion,
949                                              String implementationVendor,
950                                              URL sealBase) {
951                     try {
952                         return (Package) definePackage.invoke(accessor,
953                                 classLoader,
954                                 name,
955                                 specificationTitle,
956                                 specificationVersion,
957                                 specificationVendor,
958                                 implementationTitle,
959                                 implementationVersion,
960                                 implementationVendor,
961                                 sealBase);
962                     } catch (IllegalAccessException exception) {
963                         throw new IllegalStateException("Could not access (accessor)::definePackage", exception);
964                     } catch (InvocationTargetException exception) {
965                         throw new IllegalStateException("Error invoking (accessor)::definePackage", exception.getCause());
966                     }
967                 }
968             }
969
970             /**
971              * A dispatcher implementation that uses {@code sun.misc.Unsafe#putBoolean} to set the {@link AccessibleObject} field
972              * for making methods accessible.
973              */

974             abstract class UsingUnsafeOverride implements Dispatcher, Initializable {
975
976                 /**
977                  * An instance of {@link ClassLoader#findLoadedClass(String)}.
978                  */

979                 protected final Method findLoadedClass;
980
981                 /**
982                  * An instance of {@link ClassLoader#defineClass(String, byte[], intint, ProtectionDomain)}.
983                  */

984                 protected final Method defineClass;
985
986                 /**
987                  * An instance of {@link ClassLoader#getPackage(String)} or {@code ClassLoader#getDefinedPackage(String)}.
988                  */

989                 protected final Method getPackage;
990
991                 /**
992                  * An instance of {@link ClassLoader#definePackage(String, String, String, String, String, String, String, URL)}.
993                  */

994                 protected final Method definePackage;
995
996                 /**
997                  * Creates a new unsafe field injecting injection dispatcher.
998                  *
999                  * @param findLoadedClass An instance of {@link ClassLoader#findLoadedClass(String)}.
1000                  * @param defineClass     An instance of {@link ClassLoader#defineClass(String, byte[], intint, ProtectionDomain)}.
1001                  * @param getPackage      An instance of {@link ClassLoader#getPackage(String)} or {@code ClassLoader#getDefinedPackage(String)}.
1002                  * @param definePackage   An instance of {@link ClassLoader#definePackage(String, String, String, String, String, String, String, URL)}.
1003                  */

1004                 protected UsingUnsafeOverride(Method findLoadedClass,
1005                                               Method defineClass,
1006                                               Method getPackage,
1007                                               Method definePackage) {
1008                     this.findLoadedClass = findLoadedClass;
1009                     this.defineClass = defineClass;
1010                     this.getPackage = getPackage;
1011                     this.definePackage = definePackage;
1012                 }
1013
1014                 /**
1015                  * Creates a new initializable class injector using an unsafe field injection.
1016                  *
1017                  * @return An appropriate initializable.
1018                  * @throws Exception If the injector cannot be created.
1019                  */

1020                 @SuppressFBWarnings(value = "DP_DO_INSIDE_DO_PRIVILEGED", justification = "Privilege is explicit caller responsibility")
1021                 protected static Initializable make() throws Exception {
1022                     if (Boolean.getBoolean(UsingUnsafe.SAFE_PROPERTY)) {
1023                         return new Initializable.Unavailable("Use of Unsafe was disabled by system property");
1024                     }
1025                     Class<?> unsafeType = Class.forName("sun.misc.Unsafe");
1026                     Field theUnsafe = unsafeType.getDeclaredField("theUnsafe");
1027                     theUnsafe.setAccessible(true);
1028                     Object unsafe = theUnsafe.get(null);
1029                     Field override;
1030                     try {
1031                         override = AccessibleObject.class.getDeclaredField("override");
1032                     } catch (NoSuchFieldException ignored) {
1033                         // Since Java 12, the override field is hidden from the reflection API. To circumvent this, we
1034                         // create a mirror class of AccessibleObject that defines the same fields and has the same field
1035                         // layout such that the override field will receive the same class offset. Doing so, we can write to
1036                         // the offset location and still set a value to it, despite it being hidden from the reflection API.
1037                         override = new ByteBuddy()
1038                                 .redefine(AccessibleObject.class)
1039                                 .name("net.bytebuddy.mirror." + AccessibleObject.class.getSimpleName())
1040                                 .noNestMate()
1041                                 .visit(new MemberRemoval().stripInvokables(any()))
1042                                 .make()
1043                                 .load(AccessibleObject.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
1044                                 .getLoaded()
1045                                 .getDeclaredField("override");
1046                     }
1047                     long offset = (Long) unsafeType
1048                             .getMethod("objectFieldOffset", Field.class)
1049                             .invoke(unsafe, override);
1050                     Method putBoolean = unsafeType.getMethod("putBoolean", Object.classlong.classboolean.class);
1051                     Method getPackage;
1052                     if (JavaModule.isSupported()) { // Avoid accidental lookup of method with same name in Java 8 J9 VM.
1053                         try {
1054                             getPackage = ClassLoader.class.getMethod("getDefinedPackage", String.class);
1055                         } catch (NoSuchMethodException ignored) {
1056                             getPackage = ClassLoader.class.getDeclaredMethod("getPackage", String.class);
1057                             putBoolean.invoke(unsafe, getPackage, offset, true);
1058                         }
1059                     } else {
1060                         getPackage = ClassLoader.class.getDeclaredMethod("getPackage", String.class);
1061                         putBoolean.invoke(unsafe, getPackage, offset, true);
1062                     }
1063                     Method findLoadedClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class);
1064                     Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass",
1065                             String.class,
1066                             byte[].class,
1067                             int.class,
1068                             int.class,
1069                             ProtectionDomain.class);
1070                     Method definePackage = ClassLoader.class.getDeclaredMethod("definePackage",
1071                             String.class,
1072                             String.class,
1073                             String.class,
1074                             String.class,
1075                             String.class,
1076                             String.class,
1077                             String.class,
1078                             URL.class);
1079                     putBoolean.invoke(unsafe, defineClass, offset, true);
1080                     putBoolean.invoke(unsafe, findLoadedClass, offset, true);
1081                     putBoolean.invoke(unsafe, definePackage, offset, true);
1082                     try {
1083                         Method getClassLoadingLock = ClassLoader.class.getDeclaredMethod("getClassLoadingLock", String.class);
1084                         putBoolean.invoke(unsafe, getClassLoadingLock, offset, true);
1085                         return new ForJava7CapableVm(findLoadedClass,
1086                                 defineClass,
1087                                 getPackage,
1088                                 definePackage,
1089                                 getClassLoadingLock);
1090                     } catch (NoSuchMethodException ignored) {
1091                         return new ForLegacyVm(findLoadedClass, defineClass, getPackage, definePackage);
1092                     }
1093                 }
1094
1095                 /**
1096                  * {@inheritDoc}
1097                  */

1098                 public boolean isAvailable() {
1099                     return true;
1100                 }
1101
1102                 /**
1103                  * {@inheritDoc}
1104                  */

1105                 public Dispatcher initialize() {
1106                     SecurityManager securityManager = System.getSecurityManager();
1107                     if (securityManager != null) {
1108                         try {
1109                             securityManager.checkPermission(SUPPRESS_ACCESS_CHECKS);
1110                         } catch (Exception exception) {
1111                             return new Dispatcher.Unavailable(exception.getMessage());
1112                         }
1113                     }
1114                     return this;
1115                 }
1116
1117                 /**
1118                  * {@inheritDoc}
1119                  */

1120                 public Class<?> findClass(ClassLoader classLoader, String name) {
1121                     try {
1122                         return (Class<?>) findLoadedClass.invoke(classLoader, name);
1123                     } catch (IllegalAccessException exception) {
1124                         throw new IllegalStateException("Could not access java.lang.ClassLoader#findClass", exception);
1125                     } catch (InvocationTargetException exception) {
1126                         throw new IllegalStateException("Error invoking java.lang.ClassLoader#findClass", exception.getCause());
1127                     }
1128                 }
1129
1130                 /**
1131                  * {@inheritDoc}
1132                  */

1133                 public Class<?> defineClass(ClassLoader classLoader, String name, byte[] binaryRepresentation, ProtectionDomain protectionDomain) {
1134                     try {
1135                         return (Class<?>) defineClass.invoke(classLoader, name, binaryRepresentation, 0, binaryRepresentation.length, protectionDomain);
1136                     } catch (IllegalAccessException exception) {
1137                         throw new IllegalStateException("Could not access java.lang.ClassLoader#defineClass", exception);
1138                     } catch (InvocationTargetException exception) {
1139                         throw new IllegalStateException("Error invoking java.lang.ClassLoader#defineClass", exception.getCause());
1140                     }
1141                 }
1142
1143                 /**
1144                  * {@inheritDoc}
1145                  */

1146                 public Package getPackage(ClassLoader classLoader, String name) {
1147                     try {
1148                         return (Package) getPackage.invoke(classLoader, name);
1149                     } catch (IllegalAccessException exception) {
1150                         throw new IllegalStateException("Could not access java.lang.ClassLoader#getPackage", exception);
1151                     } catch (InvocationTargetException exception) {
1152                         throw new IllegalStateException("Error invoking java.lang.ClassLoader#getPackage", exception.getCause());
1153                     }
1154                 }
1155
1156                 /**
1157                  * {@inheritDoc}
1158                  */

1159                 public Package definePackage(ClassLoader classLoader,
1160                                              String name,
1161                                              String specificationTitle,
1162                                              String specificationVersion,
1163                                              String specificationVendor,
1164                                              String implementationTitle,
1165                                              String implementationVersion,
1166                                              String implementationVendor,
1167                                              URL sealBase) {
1168                     try {
1169                         return (Package) definePackage.invoke(classLoader,
1170                                 name,
1171                                 specificationTitle,
1172                                 specificationVersion,
1173                                 specificationVendor,
1174                                 implementationTitle,
1175                                 implementationVersion,
1176                                 implementationVendor,
1177                                 sealBase);
1178                     } catch (IllegalAccessException exception) {
1179                         throw new IllegalStateException("Could not access java.lang.ClassLoader#definePackage", exception);
1180                     } catch (InvocationTargetException exception) {
1181                         throw new IllegalStateException("Error invoking java.lang.ClassLoader#definePackage", exception.getCause());
1182                     }
1183                 }
1184
1185                 /**
1186                  * A resolved class dispatcher using unsafe field injection for a class injector on a VM running at least Java 7.
1187                  */

1188                 @HashCodeAndEqualsPlugin.Enhance
1189                 protected static class ForJava7CapableVm extends UsingUnsafeOverride {
1190
1191                     /**
1192                      * An instance of {@code ClassLoader#getClassLoadingLock(String)}.
1193                      */

1194                     private final Method getClassLoadingLock;
1195
1196                     /**
1197                      * Creates a new resolved class injector using unsafe field injection for a VM running at least Java 7.
1198                      *
1199                      * @param getClassLoadingLock An instance of {@code ClassLoader#getClassLoadingLock(String)}.
1200                      * @param findLoadedClass     An instance of {@link ClassLoader#findLoadedClass(String)}.
1201                      * @param defineClass         An instance of {@link ClassLoader#defineClass(String, byte[], intint, ProtectionDomain)}.
1202                      * @param getPackage          An instance of {@link ClassLoader#getPackage(String)} or {@code ClassLoader#getDefinedPackage(String)}.
1203                      * @param definePackage       An instance of {@link ClassLoader#definePackage(String, String, String, String, String, String, String, URL)}.
1204                      */

1205                     protected ForJava7CapableVm(Method findLoadedClass,
1206                                                 Method defineClass,
1207                                                 Method getPackage,
1208                                                 Method definePackage,
1209                                                 Method getClassLoadingLock) {
1210                         super(findLoadedClass, defineClass, getPackage, definePackage);
1211                         this.getClassLoadingLock = getClassLoadingLock;
1212                     }
1213
1214                     /**
1215                      * {@inheritDoc}
1216                      */

1217                     public Object getClassLoadingLock(ClassLoader classLoader, String name) {
1218                         try {
1219                             return getClassLoadingLock.invoke(classLoader, name);
1220                         } catch (IllegalAccessException exception) {
1221                             throw new IllegalStateException("Could not access java.lang.ClassLoader#getClassLoadingLock", exception);
1222                         } catch (InvocationTargetException exception) {
1223                             throw new IllegalStateException("Error invoking java.lang.ClassLoader#getClassLoadingLock", exception.getCause());
1224                         }
1225                     }
1226                 }
1227
1228                 /**
1229                  * A resolved class dispatcher using unsafe field injection for a class injector prior to Java 7.
1230                  */

1231                 protected static class ForLegacyVm extends UsingUnsafeOverride {
1232
1233                     /**
1234                      * Creates a new resolved class injector using unsafe field injection for a VM prior to Java 7.
1235                      *
1236                      * @param findLoadedClass An instance of {@link ClassLoader#findLoadedClass(String)}.
1237                      * @param defineClass     An instance of {@link ClassLoader#defineClass(String, byte[], intint, ProtectionDomain)}.
1238                      * @param getPackage      An instance of {@link ClassLoader#getPackage(String)} or {@code ClassLoader#getDefinedPackage(String)}.
1239                      * @param definePackage   An instance of {@link ClassLoader#definePackage(String, String, String, String, String, String, String, URL)}.
1240                      */

1241                     protected ForLegacyVm(Method findLoadedClass,
1242                                           Method defineClass,
1243                                           Method getPackage,
1244                                           Method definePackage) {
1245                         super(findLoadedClass, defineClass, getPackage, definePackage);
1246                     }
1247
1248                     /**
1249                      * {@inheritDoc}
1250                      */

1251                     public Object getClassLoadingLock(ClassLoader classLoader, String name) {
1252                         return classLoader;
1253                     }
1254                 }
1255             }
1256
1257             /**
1258              * Represents an unsuccessfully loaded method lookup.
1259              */

1260             @HashCodeAndEqualsPlugin.Enhance
1261             class Unavailable implements Dispatcher {
1262
1263                 /**
1264                  * The error message being displayed.
1265                  */

1266                 private final String message;
1267
1268                 /**
1269                  * Creates a dispatcher for a VM that does not support reflective injection.
1270                  *
1271                  * @param message The error message being displayed.
1272                  */

1273                 protected Unavailable(String message) {
1274                     this.message = message;
1275                 }
1276
1277                 /**
1278                  * {@inheritDoc}
1279                  */

1280                 public Object getClassLoadingLock(ClassLoader classLoader, String name) {
1281                     return classLoader;
1282                 }
1283
1284                 /**
1285                  * {@inheritDoc}
1286                  */

1287                 public Class<?> findClass(ClassLoader classLoader, String name) {
1288                     try {
1289                         return classLoader.loadClass(name);
1290                     } catch (ClassNotFoundException ignored) {
1291                         return UNDEFINED;
1292                     }
1293                 }
1294
1295                 /**
1296                  * {@inheritDoc}
1297                  */

1298                 public Class<?> defineClass(ClassLoader classLoader, String name, byte[] binaryRepresentation, ProtectionDomain protectionDomain) {
1299                     throw new UnsupportedOperationException("Cannot define class using reflection: " + message);
1300                 }
1301
1302                 /**
1303                  * {@inheritDoc}
1304                  */

1305                 public Package getPackage(ClassLoader classLoader, String name) {
1306                     throw new UnsupportedOperationException("Cannot get package using reflection: " + message);
1307                 }
1308
1309                 /**
1310                  * {@inheritDoc}
1311                  */

1312                 public Package definePackage(ClassLoader classLoader,
1313                                              String name,
1314                                              String specificationTitle,
1315                                              String specificationVersion,
1316                                              String specificationVendor,
1317                                              String implementationTitle,
1318                                              String implementationVersion,
1319                                              String implementationVendor,
1320                                              URL sealBase) {
1321                     throw new UnsupportedOperationException("Cannot define package using injection: " + message);
1322                 }
1323             }
1324         }
1325     }
1326
1327     /**
1328      * <p>
1329      * A class injector that uses a {@code java.lang.invoke.MethodHandles$Lookup} object for defining a class.
1330      * </p>
1331      * <p>
1332      * <b>Important</b>: This functionality is only available starting from Java 9.
1333      * </p>
1334      */

1335     @HashCodeAndEqualsPlugin.Enhance
1336     class UsingLookup extends AbstractBase {
1337
1338         /**
1339          * The dispatcher to interacting with method handles.
1340          */

1341         private static final Dispatcher DISPATCHER = AccessController.doPrivileged(Dispatcher.Creator.INSTANCE);
1342
1343         /**
1344          * Indicates a lookup instance's package lookup mode.
1345          */

1346         private static final int PACKAGE_LOOKUP = 0x8;
1347
1348         /**
1349          * The {@code java.lang.invoke.MethodHandles$Lookup} to use.
1350          */

1351         private final Object lookup;
1352
1353         /**
1354          * Creates a new class injector using a lookup instance.
1355          *
1356          * @param lookup The {@code java.lang.invoke.MethodHandles$Lookup} instance to use.
1357          */

1358         protected UsingLookup(Object lookup) {
1359             this.lookup = lookup;
1360         }
1361
1362         /**
1363          * Creates class injector that defines a class using a method handle lookup.
1364          *
1365          * @param lookup The {@code java.lang.invoke.MethodHandles$Lookup} instance to use.
1366          * @return An appropriate class injector.
1367          */

1368         public static UsingLookup of(Object lookup) {
1369             if (!DISPATCHER.isAlive()) {
1370                 throw new IllegalStateException("The current VM does not support class definition via method handle lookups");
1371             } else if (!JavaType.METHOD_HANDLES_LOOKUP.isInstance(lookup)) {
1372                 throw new IllegalArgumentException("Not a method handle lookup: " + lookup);
1373             } else if ((DISPATCHER.lookupModes(lookup) & PACKAGE_LOOKUP) == 0) {
1374                 throw new IllegalArgumentException("Lookup does not imply package-access: " + lookup);
1375             }
1376             return new UsingLookup(lookup);
1377         }
1378
1379         /**
1380          * Returns the lookup type this injector is based upon.
1381          *
1382          * @return The lookup type.
1383          */

1384         public Class<?> lookupType() {
1385             return DISPATCHER.lookupType(lookup);
1386         }
1387
1388         /**
1389          * Resolves this injector to use the supplied type's scope.
1390          *
1391          * @param type The type to resolve the access scope for.
1392          * @return An new injector with the specified scope.
1393          */

1394         public UsingLookup in(Class<?> type) {
1395             return new UsingLookup(DISPATCHER.resolve(lookup, type));
1396         }
1397
1398         /**
1399          * {@inheritDoc}
1400          */

1401         public boolean isAlive() {
1402             return isAvailable();
1403         }
1404
1405         /**
1406          * {@inheritDoc}
1407          */

1408         public Map<String, Class<?>> injectRaw(Map<? extends String, byte[]> types) {
1409             String expectedPackage = TypeDescription.ForLoadedType.of(lookupType()).getPackage().getName();
1410             Map<String, Class<?>> result = new HashMap<String, Class<?>>();
1411             for (Map.Entry<? extends String, byte[]> entry : types.entrySet()) {
1412                 int index = entry.getKey().lastIndexOf('.');
1413                 if (!expectedPackage.equals(index == -1 ? "" : entry.getKey().substring(0, index))) {
1414                     throw new IllegalArgumentException(entry.getKey() + " must be defined in the same package as " + lookup);
1415                 }
1416                 result.put(entry.getKey(), DISPATCHER.defineClass(lookup, entry.getValue()));
1417             }
1418             return result;
1419         }
1420
1421         /**
1422          * Checks if the current VM is capable of defining classes using a method handle lookup.
1423          *
1424          * @return {@code trueif the current VM is capable of defining classes using a lookup.
1425          */

1426         public static boolean isAvailable() {
1427             return DISPATCHER.isAlive();
1428         }
1429
1430         /**
1431          * A dispatcher for interacting with a method handle lookup.
1432          */

1433         protected interface Dispatcher {
1434
1435             /**
1436              * Indicates if this dispatcher is available on the current VM.
1437              *
1438              * @return {@code trueif this dispatcher is alive.
1439              */

1440             boolean isAlive();
1441
1442             /**
1443              * Returns the lookup type for a given method handle lookup.
1444              *
1445              * @param lookup The lookup instance.
1446              * @return The lookup type.
1447              */

1448             Class<?> lookupType(Object lookup);
1449
1450             /**
1451              * Returns a lookup objects lookup types.
1452              *
1453              * @param lookup The lookup instance.
1454              * @return The modifiers indicating the instance's lookup modes.
1455              */

1456             int lookupModes(Object lookup);
1457
1458             /**
1459              * Resolves the supplied lookup instance's access scope for the supplied type.
1460              *
1461              * @param lookup The lookup to use.
1462              * @param type   The type to resolve the scope for.
1463              * @return An appropriate lookup instance.
1464              */

1465             Object resolve(Object lookup, Class<?> type);
1466
1467             /**
1468              * Defines a class.
1469              *
1470              * @param lookup               The {@code java.lang.invoke.MethodHandles$Lookup} instance to use.
1471              * @param binaryRepresentation The defined class's binary representation.
1472              * @return The defined class.
1473              */

1474             Class<?> defineClass(Object lookup, byte[] binaryRepresentation);
1475
1476             /**
1477              * An action for defining a dispatcher.
1478              */

1479             enum Creator implements PrivilegedAction<Dispatcher> {
1480
1481                 /**
1482                  * The singleton instance.
1483                  */

1484                 INSTANCE;
1485
1486                 /**
1487                  * {@inheritDoc}
1488                  */

1489                 @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback")
1490                 public Dispatcher run() {
1491                     try {
1492                         Class<?> lookup = JavaType.METHOD_HANDLES_LOOKUP.load();
1493                         return new Dispatcher.ForJava9CapableVm(JavaType.METHOD_HANDLES.load().getMethod("privateLookupIn", Class.class, lookup),
1494                                 lookup.getMethod("lookupClass"),
1495                                 lookup.getMethod("lookupModes"),
1496                                 lookup.getMethod("defineClass"byte[].class));
1497                     } catch (Exception ignored) {
1498                         return Dispatcher.ForLegacyVm.INSTANCE;
1499                     }
1500                 }
1501             }
1502
1503             /**
1504              * A dispatcher for a legacy VM that does not support class definition via method handles.
1505              */

1506             enum ForLegacyVm implements Dispatcher {
1507
1508                 /**
1509                  * The singleton instance.
1510                  */

1511                 INSTANCE;
1512
1513                 /**
1514                  * {@inheritDoc}
1515                  */

1516                 public boolean isAlive() {
1517                     return false;
1518                 }
1519
1520                 /**
1521                  * {@inheritDoc}
1522                  */

1523                 public Class<?> lookupType(Object lookup) {
1524                     throw new IllegalStateException("Cannot dispatch method for java.lang.invoke.MethodHandles$Lookup");
1525                 }
1526
1527                 /**
1528                  * {@inheritDoc}
1529                  */

1530                 public int lookupModes(Object lookup) {
1531                     throw new IllegalStateException("Cannot dispatch method for java.lang.invoke.MethodHandles$Lookup");
1532                 }
1533
1534                 /**
1535                  * {@inheritDoc}
1536                  */

1537                 public Object resolve(Object lookup, Class<?> type) {
1538                     throw new IllegalStateException("Cannot dispatch method for java.lang.invoke.MethodHandles");
1539                 }
1540
1541                 /**
1542                  * {@inheritDoc}
1543                  */

1544                 public Class<?> defineClass(Object lookup, byte[] binaryRepresentation) {
1545                     throw new IllegalStateException("Cannot dispatch method for java.lang.invoke.MethodHandles$Lookup");
1546                 }
1547             }
1548
1549             /**
1550              * A dispatcher for a Java 9 capable VM that supports class definition via method handles.
1551              */

1552             @HashCodeAndEqualsPlugin.Enhance
1553             class ForJava9CapableVm implements Dispatcher {
1554
1555                 /**
1556                  * An empty array that can be used to indicate no arguments to avoid an allocation on a reflective call.
1557                  */

1558                 private static final Object[] NO_ARGUMENTS = new Object[0];
1559
1560                 /**
1561                  * The {@code java.lang.invoke.MethodHandles$#privateLookupIn} method.
1562                  */

1563                 private final Method privateLookupIn;
1564
1565                 /**
1566                  * The {@code java.lang.invoke.MethodHandles$Lookup#lookupClass} method.
1567                  */

1568                 private final Method lookupClass;
1569
1570                 /**
1571                  * The {@code java.lang.invoke.MethodHandles$Lookup#lookupModes} method.
1572                  */

1573                 private final Method lookupModes;
1574
1575                 /**
1576                  * The {@code java.lang.invoke.MethodHandles$Lookup#defineClass} method.
1577                  */

1578                 private final Method defineClass;
1579
1580                 /**
1581                  * Creates a new dispatcher for a Java 9 capable VM.
1582                  *
1583                  * @param privateLookupIn The {@code java.lang.invoke.MethodHandles$#privateLookupIn} method.
1584                  * @param lookupClass     The {@code java.lang.invoke.MethodHandles$Lookup#lookupClass} method.
1585                  * @param lookupModes     The {@code java.lang.invoke.MethodHandles$Lookup#lookupModes} method.
1586                  * @param defineClass     The {@code java.lang.invoke.MethodHandles$Lookup#defineClass} method.
1587                  */

1588                 protected ForJava9CapableVm(Method privateLookupIn, Method lookupClass, Method lookupModes, Method defineClass) {
1589                     this.privateLookupIn = privateLookupIn;
1590                     this.lookupClass = lookupClass;
1591                     this.lookupModes = lookupModes;
1592                     this.defineClass = defineClass;
1593                 }
1594
1595                 /**
1596                  * {@inheritDoc}
1597                  */

1598                 public boolean isAlive() {
1599                     return true;
1600                 }
1601
1602                 /**
1603                  * {@inheritDoc}
1604                  */

1605                 public Class<?> lookupType(Object lookup) {
1606                     try {
1607                         return (Class<?>) lookupClass.invoke(lookup, NO_ARGUMENTS);
1608                     } catch (IllegalAccessException exception) {
1609                         throw new IllegalStateException("Cannot access java.lang.invoke.MethodHandles$Lookup#lookupClass", exception);
1610                     } catch (InvocationTargetException exception) {
1611                         throw new IllegalStateException("Error invoking java.lang.invoke.MethodHandles$Lookup#lookupClass", exception.getCause());
1612                     }
1613                 }
1614
1615                 /**
1616                  * {@inheritDoc}
1617                  */

1618                 public int lookupModes(Object lookup) {
1619                     try {
1620                         return (Integer) lookupModes.invoke(lookup, NO_ARGUMENTS);
1621                     } catch (IllegalAccessException exception) {
1622                         throw new IllegalStateException("Cannot access java.lang.invoke.MethodHandles$Lookup#lookupModes", exception);
1623                     } catch (InvocationTargetException exception) {
1624                         throw new IllegalStateException("Error invoking java.lang.invoke.MethodHandles$Lookup#lookupModes", exception.getCause());
1625                     }
1626                 }
1627
1628                 /**
1629                  * {@inheritDoc}
1630                  */

1631                 public Object resolve(Object lookup, Class<?> type) {
1632                     try {
1633                         return privateLookupIn.invoke(null, type, lookup);
1634                     } catch (IllegalAccessException exception) {
1635                         throw new IllegalStateException("Cannot access java.lang.invoke.MethodHandles#privateLookupIn", exception);
1636                     } catch (InvocationTargetException exception) {
1637                         throw new IllegalStateException("Error invoking java.lang.invoke.MethodHandles#privateLookupIn", exception.getCause());
1638                     }
1639                 }
1640
1641                 /**
1642                  * {@inheritDoc}
1643                  */

1644                 public Class<?> defineClass(Object lookup, byte[] binaryRepresentation) {
1645                     try {
1646                         return (Class<?>) defineClass.invoke(lookup, (Object) binaryRepresentation);
1647                     } catch (IllegalAccessException exception) {
1648                         throw new IllegalStateException("Cannot access java.lang.invoke.MethodHandles$Lookup#defineClass", exception);
1649                     } catch (InvocationTargetException exception) {
1650                         throw new IllegalStateException("Error invoking java.lang.invoke.MethodHandles$Lookup#defineClass", exception.getCause());
1651                     }
1652                 }
1653             }
1654         }
1655     }
1656
1657     /**
1658      * A class injector that uses {@code sun.misc.Unsafe} to inject classes.
1659      */

1660     @HashCodeAndEqualsPlugin.Enhance
1661     class UsingUnsafe extends AbstractBase {
1662
1663         /**
1664          * If this property is set, Byte Buddy does not make use of any {@code Unsafe} class.
1665          */

1666         public static final String SAFE_PROPERTY = "net.bytebuddy.safe";
1667
1668         /**
1669          * The dispatcher to use.
1670          */

1671         private static final Dispatcher.Initializable DISPATCHER = AccessController.doPrivileged(Dispatcher.CreationAction.INSTANCE);
1672
1673         /**
1674          * A lock for the bootstrap loader when injecting code.
1675          */

1676         private static final Object BOOTSTRAP_LOADER_LOCK = new Object();
1677
1678         /**
1679          * The class loader to inject classes into or {@code nullfor the bootstrap loader.
1680          */

1681         @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
1682         private final ClassLoader classLoader;
1683
1684         /**
1685          * The protection domain to use or {@code nullfor no protection domain.
1686          */

1687         @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
1688         private final ProtectionDomain protectionDomain;
1689
1690         /**
1691          * The dispatcher to use.
1692          */

1693         private final Dispatcher.Initializable dispatcher;
1694
1695         /**
1696          * Creates a new unsafe injector for the given class loader with a default protection domain.
1697          *
1698          * @param classLoader The class loader to inject classes into or {@code nullfor the bootstrap loader.
1699          */

1700         public UsingUnsafe(ClassLoader classLoader) {
1701             this(classLoader, ClassLoadingStrategy.NO_PROTECTION_DOMAIN);
1702         }
1703
1704         /**
1705          * Creates a new unsafe injector for the given class loader with a default protection domain.
1706          *
1707          * @param classLoader      The class loader to inject classes into or {@code nullfor the bootstrap loader.
1708          * @param protectionDomain The protection domain to use or {@code nullfor no protection domain.
1709          */

1710         public UsingUnsafe(ClassLoader classLoader, ProtectionDomain protectionDomain) {
1711             this(classLoader, protectionDomain, DISPATCHER);
1712         }
1713
1714         /**
1715          * Creates a new unsafe injector for the given class loader with a default protection domain.
1716          *
1717          * @param classLoader      The class loader to inject classes into or {@code nullfor the bootstrap loader.
1718          * @param protectionDomain The protection domain to use or {@code nullfor no protection domain.
1719          * @param dispatcher       The dispatcher to use.
1720          */

1721         protected UsingUnsafe(ClassLoader classLoader, ProtectionDomain protectionDomain, Dispatcher.Initializable dispatcher) {
1722             this.classLoader = classLoader;
1723             this.protectionDomain = protectionDomain;
1724             this.dispatcher = dispatcher;
1725         }
1726
1727         /**
1728          * {@inheritDoc}
1729          */

1730         public boolean isAlive() {
1731             return dispatcher.isAvailable();
1732         }
1733
1734         /**
1735          * {@inheritDoc}
1736          */

1737         public Map<String, Class<?>> injectRaw(Map<? extends String, byte[]> types) {
1738             Dispatcher dispatcher = this.dispatcher.initialize();
1739             Map<String, Class<?>> result = new HashMap<String, Class<?>>();
1740             synchronized (classLoader == null
1741                     ? BOOTSTRAP_LOADER_LOCK
1742                     : classLoader) {
1743                 for (Map.Entry<? extends String, byte[]> entry : types.entrySet()) {
1744                     try {
1745                         result.put(entry.getKey(), Class.forName(entry.getKey(), false, classLoader));
1746                     } catch (ClassNotFoundException ignored) {
1747                         result.put(entry.getKey(), dispatcher.defineClass(classLoader, entry.getKey(), entry.getValue(), protectionDomain));
1748                     }
1749                 }
1750             }
1751             return result;
1752         }
1753
1754         /**
1755          * Checks if unsafe class injection is available on the current VM.
1756          *
1757          * @return {@code trueif unsafe class injection is available on the current VM.
1758          */

1759         public static boolean isAvailable() {
1760             return DISPATCHER.isAvailable();
1761         }
1762
1763         /**
1764          * Returns an unsafe class injector for the system class loader.
1765          *
1766          * @return A class injector for the system class loader.
1767          */

1768         public static ClassInjector ofSystemLoader() {
1769             return new UsingUnsafe(ClassLoader.getSystemClassLoader());
1770         }
1771
1772         /**
1773          * Returns an unsafe class injector for the platform class loader. For VMs of version 8 or older,
1774          * the extension class loader is represented instead.
1775          *
1776          * @return A class injector for the platform class loader.
1777          */

1778         public static ClassInjector ofPlatformLoader() {
1779             return new UsingUnsafe(ClassLoader.getSystemClassLoader().getParent());
1780         }
1781
1782         /**
1783          * Returns an unsafe class injector for the boot class loader.
1784          *
1785          * @return A class injector for the boot loader.
1786          */

1787         public static ClassInjector ofBootLoader() {
1788             return new UsingUnsafe(ClassLoadingStrategy.BOOTSTRAP_LOADER);
1789         }
1790
1791         /**
1792          * A dispatcher for using {@code sun.misc.Unsafe}.
1793          */

1794         protected interface Dispatcher {
1795
1796             /**
1797              * Defines a class.
1798              *
1799              * @param classLoader          The class loader to inject the class into.
1800              * @param name                 The type's name.
1801              * @param binaryRepresentation The type's binary representation.
1802              * @param protectionDomain     The type's protection domain.
1803              * @return The defined class.
1804              */

1805             Class<?> defineClass(ClassLoader classLoader, String name, byte[] binaryRepresentation, ProtectionDomain protectionDomain);
1806
1807             /**
1808              * A class injection dispatcher that is not yet initialized.
1809              */

1810             interface Initializable {
1811
1812                 /**
1813                  * Checks if unsafe class injection is available on the current VM.
1814                  *
1815                  * @return {@code trueif unsafe class injection is available.
1816                  */

1817                 boolean isAvailable();
1818
1819                 /**
1820                  * Initializes the dispatcher.
1821                  *
1822                  * @return The initialized dispatcher.
1823                  */

1824                 Dispatcher initialize();
1825             }
1826
1827             /**
1828              * A privileged action for creating a dispatcher.
1829              */

1830             enum CreationAction implements PrivilegedAction<Initializable> {
1831
1832                 /**
1833                  * The singleton instance.
1834                  */

1835                 INSTANCE;
1836
1837                 /**
1838                  * {@inheritDoc}
1839                  */

1840                 @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback")
1841                 public Initializable run() {
1842                     if (Boolean.getBoolean(SAFE_PROPERTY)) {
1843                         return new Unavailable("Use of Unsafe was disabled by system property");
1844                     }
1845                     try {
1846                         Class<?> unsafeType = Class.forName("sun.misc.Unsafe");
1847                         Field theUnsafe = unsafeType.getDeclaredField("theUnsafe");
1848                         theUnsafe.setAccessible(true);
1849                         Object unsafe = theUnsafe.get(null);
1850                         try {
1851                             Method defineClass = unsafeType.getMethod("defineClass",
1852                                     String.class,
1853                                     byte[].class,
1854                                     int.class,
1855                                     int.class,
1856                                     ClassLoader.class,
1857                                     ProtectionDomain.class);
1858                             defineClass.setAccessible(true);
1859                             return new Enabled(unsafe, defineClass);
1860                         } catch (Exception exception) {
1861                             try {
1862                                 Field override;
1863                                 try {
1864                                     override = AccessibleObject.class.getDeclaredField("override");
1865                                 } catch (NoSuchFieldException ignored) {
1866                                     // Since Java 12, the override field is hidden from the reflection API. To circumvent this, we
1867                                     // create a mirror class of AccessibleObject that defines the same fields and has the same field
1868                                     // layout such that the override field will receive the same class offset. Doing so, we can write to
1869                                     // the offset location and still set a value to it, despite it being hidden from the reflection API.
1870                                     override = new ByteBuddy()
1871                                             .redefine(AccessibleObject.class)
1872                                             .name("net.bytebuddy.mirror." + AccessibleObject.class.getSimpleName())
1873                                             .noNestMate()
1874                                             .visit(new MemberRemoval().stripInvokables(any()))
1875                                             .make()
1876                                             .load(AccessibleObject.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
1877                                             .getLoaded()
1878                                             .getDeclaredField("override");
1879                                 }
1880                                 long offset = (Long) unsafeType
1881                                         .getMethod("objectFieldOffset", Field.class)
1882                                         .invoke(unsafe, override);
1883                                 Method putBoolean = unsafeType.getMethod("putBoolean", Object.classlong.classboolean.class);
1884                                 Class<?> internalUnsafe = Class.forName("jdk.internal.misc.Unsafe");
1885                                 Field theUnsafeInternal = internalUnsafe.getDeclaredField("theUnsafe");
1886                                 putBoolean.invoke(unsafe, theUnsafeInternal, offset, true);
1887                                 Method defineClassInternal = internalUnsafe.getMethod("defineClass",
1888                                         String.class,
1889                                         byte[].class,
1890                                         int.class,
1891                                         int.class,
1892                                         ClassLoader.class,
1893                                         ProtectionDomain.class);
1894                                 putBoolean.invoke(unsafe, defineClassInternal, offset, true);
1895                                 return new Enabled(theUnsafeInternal.get(null), defineClassInternal);
1896                             } catch (Exception ignored) {
1897                                 throw exception;
1898                             }
1899                         }
1900                     } catch (Exception exception) {
1901                         return new Unavailable(exception.getMessage());
1902                     }
1903                 }
1904             }
1905
1906             /**
1907              * An enabled dispatcher.
1908              */

1909             @HashCodeAndEqualsPlugin.Enhance
1910             class Enabled implements Dispatcher, Initializable {
1911
1912                 /**
1913                  * An instance of {@code sun.misc.Unsafe}.
1914                  */

1915                 private final Object unsafe;
1916
1917                 /**
1918                  * The {@code sun.misc.Unsafe#defineClass} method.
1919                  */

1920                 private final Method defineClass;
1921
1922                 /**
1923                  * Creates an enabled dispatcher.
1924                  *
1925                  * @param unsafe      An instance of {@code sun.misc.Unsafe}.
1926                  * @param defineClass The {@code sun.misc.Unsafe#defineClass} method.
1927                  */

1928                 protected Enabled(Object unsafe, Method defineClass) {
1929                     this.unsafe = unsafe;
1930                     this.defineClass = defineClass;
1931                 }
1932
1933                 /**
1934                  * {@inheritDoc}
1935                  */

1936                 public boolean isAvailable() {
1937                     return true;
1938                 }
1939
1940                 /**
1941                  * {@inheritDoc}
1942                  */

1943                 public Dispatcher initialize() {
1944                     SecurityManager securityManager = System.getSecurityManager();
1945                     if (securityManager != null) {
1946                         try {
1947                             securityManager.checkPermission(SUPPRESS_ACCESS_CHECKS);
1948                         } catch (Exception exception) {
1949                             return new Unavailable(exception.getMessage());
1950                         }
1951                     }
1952                     return this;
1953                 }
1954
1955                 /**
1956                  * {@inheritDoc}
1957                  */

1958                 public Class<?> defineClass(ClassLoader classLoader, String name, byte[] binaryRepresentation, ProtectionDomain protectionDomain) {
1959                     try {
1960                         return (Class<?>) defineClass.invoke(unsafe,
1961                                 name,
1962                                 binaryRepresentation,
1963                                 0,
1964                                 binaryRepresentation.length,
1965                                 classLoader,
1966                                 protectionDomain);
1967                     } catch (IllegalAccessException exception) {
1968                         throw new IllegalStateException("Could not access Unsafe::defineClass", exception);
1969                     } catch (InvocationTargetException exception) {
1970                         throw new IllegalStateException("Error invoking Unsafe::defineClass", exception.getCause());
1971                     }
1972                 }
1973             }
1974
1975             /**
1976              * A disabled dispatcher.
1977              */

1978             @HashCodeAndEqualsPlugin.Enhance
1979             class Unavailable implements Dispatcher, Initializable {
1980
1981                 /**
1982                  * The reason why this dispatcher is not available.
1983                  */

1984                 private final String message;
1985
1986                 /**
1987                  * Creates a disabled dispatcher.
1988                  *
1989                  * @param message The reason why this dispatcher is not available.
1990                  */

1991                 protected Unavailable(String message) {
1992                     this.message = message;
1993                 }
1994
1995                 /**
1996                  * {@inheritDoc}
1997                  */

1998                 public boolean isAvailable() {
1999                     return false;
2000                 }
2001
2002                 /**
2003                  * {@inheritDoc}
2004                  */

2005                 public Dispatcher initialize() {
2006                     throw new UnsupportedOperationException("Could not access Unsafe class: " + message);
2007                 }
2008
2009                 /**
2010                  * {@inheritDoc}
2011                  */

2012                 public Class<?> defineClass(ClassLoader classLoader, String name, byte[] binaryRepresentation, ProtectionDomain protectionDomain) {
2013                     throw new UnsupportedOperationException("Could not access Unsafe class: " + message);
2014                 }
2015             }
2016         }
2017
2018         /**
2019          * A factory for creating a {@link ClassInjector} that uses {@code sun.misc.Unsafe} if available but attempts a fallback
2020          * to using {@code jdk.internal.misc.Unsafe} if the {@code jdk.internal} module is not resolved or unavailable.
2021          */

2022         @HashCodeAndEqualsPlugin.Enhance
2023         public static class Factory {
2024
2025             /**
2026              * The dispatcher to use.
2027              */

2028             private final Dispatcher.Initializable dispatcher;
2029
2030             /**
2031              * Creates a new factory for an unsafe class injector that uses Byte Buddy's privileges to
2032              * accessing {@code jdk.internal.misc.Unsafe} if available.
2033              */

2034             public Factory() {
2035                 this(AccessResolver.Default.INSTANCE);
2036             }
2037
2038             /**
2039              * Creates a new factory for an unsafe class injector.
2040              *
2041              * @param accessResolver The access resolver to use.
2042              */

2043             @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception is captured to trigger lazy error upon use.")
2044             public Factory(AccessResolver accessResolver) {
2045                 Dispatcher.Initializable dispatcher;
2046                 if (DISPATCHER.isAvailable()) {
2047                     dispatcher = DISPATCHER;
2048                 } else {
2049                     try {
2050                         Class<?> unsafeType = Class.forName("jdk.internal.misc.Unsafe");
2051                         Field theUnsafe = unsafeType.getDeclaredField("theUnsafe");
2052                         accessResolver.apply(theUnsafe);
2053                         Object unsafe = theUnsafe.get(null);
2054                         Method defineClass = unsafeType.getMethod("defineClass",
2055                                 String.class,
2056                                 byte[].class,
2057                                 int.class,
2058                                 int.class,
2059                                 ClassLoader.class,
2060                                 ProtectionDomain.class);
2061                         accessResolver.apply(defineClass);
2062                         dispatcher = new Dispatcher.Enabled(unsafe, defineClass);
2063                     } catch (Exception exception) {
2064                         dispatcher = new Dispatcher.Unavailable(exception.getMessage());
2065                     }
2066                 }
2067                 this.dispatcher = dispatcher;
2068             }
2069
2070             /**
2071              * Creates a new factory.
2072              *
2073              * @param dispatcher The dispatcher to use.
2074              */

2075             protected Factory(Dispatcher.Initializable dispatcher) {
2076                 this.dispatcher = dispatcher;
2077             }
2078
2079             /**
2080              * Resolves an injection strategy that uses unsafe injection if available and also attempts to open and use
2081              * {@code jdk.internal.misc.Unsafe} as a fallback. This method generates a new class and module for opening the
2082              * internal package to avoid its exposure to any non-trusted code.
2083              *
2084              * @param instrumentation The instrumentation instance to use for opening the internal package if required.
2085              * @return An appropriate injection strategy.
2086              */

2087             public static Factory resolve(Instrumentation instrumentation) {
2088                 return resolve(instrumentation, false);
2089             }
2090
2091             /**
2092              * Resolves an injection strategy that uses unsafe injection if available and also attempts to open and use
2093              * {@code jdk.internal.misc.Unsafe} as a fallback.
2094              *
2095              * @param instrumentation The instrumentation instance to use for opening the internal package if required.
2096              * @param local           {@code falseif a new class should in a separated class loader and module should be created for
2097              *                        opening the {@code jdk.internal.misc} package. This way, the internal package is not exposed to any
2098              *                        other classes within this class's module.
2099              * @return An appropriate injection strategy.
2100              */

2101             @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception intends to trigger disabled injection strategy.")
2102             public static Factory resolve(Instrumentation instrumentation, boolean local) {
2103                 if (ClassInjector.UsingUnsafe.isAvailable() || !JavaModule.isSupported()) {
2104                     return new Factory();
2105                 } else {
2106                     try {
2107                         Class<?> type = Class.forName("jdk.internal.misc.Unsafe");
2108                         PackageDescription packageDescription = new PackageDescription.ForLoadedPackage(type.getPackage());
2109                         JavaModule source = JavaModule.ofType(type), target = JavaModule.ofType(ClassInjector.UsingUnsafe.class);
2110                         if (source.isOpened(packageDescription, target)) {
2111                             return new Factory();
2112                         } else if (local) {
2113                             JavaModule module = JavaModule.ofType(AccessResolver.Default.class);
2114                             source.modify(instrumentation,
2115                                     Collections.singleton(module),
2116                                     Collections.<String, Set<JavaModule>>emptyMap(),
2117                                     Collections.singletonMap(packageDescription.getName(), Collections.singleton(module)),
2118                                     Collections.<Class<?>>emptySet(),
2119                                     Collections.<Class<?>, List<Class<?>>>emptyMap());
2120                             return new Factory();
2121                         } else {
2122                             Class<? extends AccessResolver> resolver = new ByteBuddy()
2123                                     .subclass(AccessResolver.class)
2124                                     .method(named("apply"))
2125                                     .intercept(MethodCall.invoke(AccessibleObject.class.getMethod("setAccessible"boolean.class))
2126                                             .onArgument(0)
2127                                             .with(true))
2128                                     .make()
2129                                     .load(AccessResolver.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER.with(AccessResolver.class.getProtectionDomain()))
2130                                     .getLoaded();
2131                             JavaModule module = JavaModule.ofType(resolver);
2132                             source.modify(instrumentation,
2133                                     Collections.singleton(module),
2134                                     Collections.<String, Set<JavaModule>>emptyMap(),
2135                                     Collections.singletonMap(packageDescription.getName(), Collections.singleton(module)),
2136                                     Collections.<Class<?>>emptySet(),
2137                                     Collections.<Class<?>, List<Class<?>>>emptyMap());
2138                             return new ClassInjector.UsingUnsafe.Factory(resolver.getConstructor().newInstance());
2139                         }
2140                     } catch (Exception exception) {
2141                         return new Factory(new Dispatcher.Unavailable(exception.getMessage()));
2142                     }
2143                 }
2144             }
2145
2146             /**
2147              * Returns {@code trueif this factory creates a valid dispatcher.
2148              *
2149              * @return {@code trueif this factory creates a valid dispatcher.
2150              */

2151             public boolean isAvailable() {
2152                 return dispatcher.isAvailable();
2153             }
2154
2155             /**
2156              * Creates a new class injector for the given class loader without a {@link ProtectionDomain}.
2157              *
2158              * @param classLoader The class loader to inject into or {@code null} to inject into the bootstrap loader.
2159              * @return An appropriate class injector.
2160              */

2161             public ClassInjector make(ClassLoader classLoader) {
2162                 return make(classLoader, ClassLoadingStrategy.NO_PROTECTION_DOMAIN);
2163             }
2164
2165             /**
2166              * Creates a new class injector for the given class loader and protection domain.
2167              *
2168              * @param classLoader      The class loader to inject into or {@code null} to inject into the bootstrap loader.
2169              * @param protectionDomain The protection domain to apply or {@code nullif no protection domain should be used.
2170              * @return An appropriate class injector.
2171              */

2172             public ClassInjector make(ClassLoader classLoader, ProtectionDomain protectionDomain) {
2173                 return new UsingUnsafe(classLoader, protectionDomain, dispatcher);
2174             }
2175
2176             /**
2177              * An access resolver that invokes {@link AccessibleObject#setAccessible(boolean)} to {@code true} in a given privilege scope.
2178              */

2179             public interface AccessResolver {
2180
2181                 /**
2182                  * Applies this access resolver.
2183                  *
2184                  * @param accessibleObject The accessible object to make accessible.
2185                  */

2186                 void apply(AccessibleObject accessibleObject);
2187
2188                 /**
2189                  * A default access resolver that uses Byte Buddy's privilege scope.
2190                  */

2191                 enum Default implements AccessResolver {
2192
2193                     /**
2194                      * The singleton instance.
2195                      */

2196                     INSTANCE;
2197
2198                     /**
2199                      * {@inheritDoc}
2200                      */

2201                     public void apply(AccessibleObject accessibleObject) {
2202                         accessibleObject.setAccessible(true);
2203                     }
2204                 }
2205             }
2206         }
2207     }
2208
2209     /**
2210      * A class injector using a {@link java.lang.instrument.Instrumentation} to append to either the boot classpath
2211      * or the system class path.
2212      */

2213     @HashCodeAndEqualsPlugin.Enhance
2214     class UsingInstrumentation extends AbstractBase {
2215
2216         /**
2217          * The jar file name extension.
2218          */

2219         private static final String JAR = "jar";
2220
2221         /**
2222          * The class file extension.
2223          */

2224         private static final String CLASS_FILE_EXTENSION = ".class";
2225
2226         /**
2227          * A dispatcher for interacting with the instrumentation API.
2228          */

2229         private static final Dispatcher DISPATCHER = AccessController.doPrivileged(Dispatcher.CreationAction.INSTANCE);
2230
2231         /**
2232          * The instrumentation to use for appending to the class path or the boot path.
2233          */

2234         private final Instrumentation instrumentation;
2235
2236         /**
2237          * A representation of the target path to which classes are to be appended.
2238          */

2239         private final Target target;
2240
2241         /**
2242          * The folder to be used for storing jar files.
2243          */

2244         private final File folder;
2245
2246         /**
2247          * A random string generator for creating file names.
2248          */

2249         private final RandomString randomString;
2250
2251         /**
2252          * Creates an instrumentation-based class injector.
2253          *
2254          * @param folder          The folder to be used for storing jar files.
2255          * @param target          A representation of the target path to which classes are to be appended.
2256          * @param instrumentation The instrumentation to use for appending to the class path or the boot path.
2257          * @param randomString    The random string generator to use.
2258          */

2259         protected UsingInstrumentation(File folder,
2260                                        Target target,
2261                                        Instrumentation instrumentation,
2262                                        RandomString randomString) {
2263             this.folder = folder;
2264             this.target = target;
2265             this.instrumentation = instrumentation;
2266             this.randomString = randomString;
2267         }
2268
2269         /**
2270          * Creates an instrumentation-based class injector.
2271          *
2272          * @param folder          The folder to be used for storing jar files.
2273          * @param target          A representation of the target path to which classes are to be appended.
2274          * @param instrumentation The instrumentation to use for appending to the class path or the boot path.
2275          * @return An appropriate class injector that applies instrumentation.
2276          */

2277         public static ClassInjector of(File folder, Target target, Instrumentation instrumentation) {
2278             return new UsingInstrumentation(folder, target, instrumentation, new RandomString());
2279         }
2280
2281         /**
2282          * {@inheritDoc}
2283          */

2284         public boolean isAlive() {
2285             return isAvailable();
2286         }
2287
2288         /**
2289          * {@inheritDoc}
2290          */

2291         public Map<String, Class<?>> injectRaw(Map<? extends String, byte[]> types) {
2292             File file = new File(folder, JAR + randomString.nextString() + "." + JAR);
2293             try {
2294                 if (!file.createNewFile()) {
2295                     throw new IllegalStateException("Cannot create file " + file);
2296                 }
2297                 try {
2298                     JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(file));
2299                     try {
2300                         for (Map.Entry<? extends String, byte[]> entry : types.entrySet()) {
2301                             jarOutputStream.putNextEntry(new JarEntry(entry.getKey().replace('.', '/') + CLASS_FILE_EXTENSION));
2302                             jarOutputStream.write(entry.getValue());
2303                         }
2304                     } finally {
2305                         jarOutputStream.close();
2306                     }
2307                     JarFile jarFile = new JarFile(file, false);
2308                     try {
2309                         target.inject(instrumentation, jarFile);
2310                     } finally {
2311                         jarFile.close();
2312                     }
2313                     Map<String, Class<?>> result = new HashMap<String, Class<?>>();
2314                     for (String name : types.keySet()) {
2315                         result.put(name, Class.forName(name, false, target.getClassLoader()));
2316                     }
2317                     return result;
2318                 } finally {
2319                     if (!file.delete()) {
2320                         file.deleteOnExit();
2321                     }
2322                 }
2323             } catch (IOException exception) {
2324                 throw new IllegalStateException("Cannot write jar file to disk", exception);
2325             } catch (ClassNotFoundException exception) {
2326                 throw new IllegalStateException("Cannot load injected class", exception);
2327             }
2328         }
2329
2330         /**
2331          * Returns {@code trueif this class injector is available on this VM.
2332          *
2333          * @return {@code trueif this class injector is available on this VM.
2334          */

2335         public static boolean isAvailable() {
2336             return DISPATCHER.isAlive();
2337         }
2338
2339         /**
2340          * A dispatcher to interact with the instrumentation API.
2341          */

2342         protected interface Dispatcher {
2343
2344             /**
2345              * Returns {@code trueif this dispatcher is alive.
2346              *
2347              * @return {@code trueif this dispatcher is alive.
2348              */

2349             boolean isAlive();
2350
2351             /**
2352              * Appends a jar file to the bootstrap class loader.
2353              *
2354              * @param instrumentation The instrumentation instance to interact with.
2355              * @param jarFile         The jar file to append.
2356              */

2357             void appendToBootstrapClassLoaderSearch(Instrumentation instrumentation, JarFile jarFile);
2358
2359             /**
2360              * Appends a jar file to the system class loader.
2361              *
2362              * @param instrumentation The instrumentation instance to interact with.
2363              * @param jarFile         The jar file to append.
2364              */

2365             void appendToSystemClassLoaderSearch(Instrumentation instrumentation, JarFile jarFile);
2366
2367             /**
2368              * An action to create a dispatcher for interacting with the instrumentation API.
2369              */

2370             enum CreationAction implements PrivilegedAction<Dispatcher> {
2371
2372                 /**
2373                  * The singleton instance.
2374                  */

2375                 INSTANCE;
2376
2377                 /**
2378                  * {@inheritDoc}
2379                  */

2380                 public Dispatcher run() {
2381                     try {
2382                         Class<?> instrumentation = Class.forName("java.lang.instrument.Instrumentation");
2383                         return new ForJava6CapableVm(instrumentation.getMethod("appendToBootstrapClassLoaderSearch", JarFile.class),
2384                                 instrumentation.getMethod("appendToSystemClassLoaderSearch", JarFile.class));
2385                     } catch (ClassNotFoundException ignored) {
2386                         return ForLegacyVm.INSTANCE;
2387                     } catch (NoSuchMethodException ignored) {
2388                         return ForLegacyVm.INSTANCE;
2389                     }
2390                 }
2391             }
2392
2393             /**
2394              * A dispatcher for a legacy VM that is not capable of appending jar files using instrumentation.
2395              */

2396             enum ForLegacyVm implements Dispatcher {
2397
2398                 /**
2399                  * The singleton instance.
2400                  */

2401                 INSTANCE;
2402
2403                 /**
2404                  * {@inheritDoc}
2405                  */

2406                 public boolean isAlive() {
2407                     return false;
2408                 }
2409
2410                 /**
2411                  * {@inheritDoc}
2412                  */

2413                 public void appendToBootstrapClassLoaderSearch(Instrumentation instrumentation, JarFile jarFile) {
2414                     throw new UnsupportedOperationException("The current JVM does not support appending to the bootstrap loader");
2415                 }
2416
2417                 /**
2418                  * {@inheritDoc}
2419                  */

2420                 public void appendToSystemClassLoaderSearch(Instrumentation instrumentation, JarFile jarFile) {
2421                     throw new UnsupportedOperationException("The current JVM does not support appending to the system class loader");
2422                 }
2423             }
2424
2425             /**
2426              * A dispatcher for a VM that is capable of appending to the boot and system class loader.
2427              */

2428             @HashCodeAndEqualsPlugin.Enhance
2429             class ForJava6CapableVm implements Dispatcher {
2430
2431                 /**
2432                  * The {@code Instrumentation#appendToBootstrapClassLoaderSearch} method.
2433                  */

2434                 private final Method appendToBootstrapClassLoaderSearch;
2435
2436                 /**
2437                  * The {@code Instrumentation#appendToSystemClassLoaderSearch} method.
2438                  */

2439                 private final Method appendToSystemClassLoaderSearch;
2440
2441                 /**
2442                  * Creates a new dispatcher for a Java 6 compatible VM.
2443                  *
2444                  * @param appendToBootstrapClassLoaderSearch The {@code Instrumentation#appendToBootstrapClassLoaderSearch} method.
2445                  * @param appendToSystemClassLoaderSearch    The {@code Instrumentation#appendToSystemClassLoaderSearch} method.
2446                  */

2447                 protected ForJava6CapableVm(Method appendToBootstrapClassLoaderSearch, Method appendToSystemClassLoaderSearch) {
2448                     this.appendToBootstrapClassLoaderSearch = appendToBootstrapClassLoaderSearch;
2449                     this.appendToSystemClassLoaderSearch = appendToSystemClassLoaderSearch;
2450                 }
2451
2452                 /**
2453                  * {@inheritDoc}
2454                  */

2455                 public boolean isAlive() {
2456                     return true;
2457                 }
2458
2459                 /**
2460                  * {@inheritDoc}
2461                  */

2462                 public void appendToBootstrapClassLoaderSearch(Instrumentation instrumentation, JarFile jarFile) {
2463                     try {
2464                         appendToBootstrapClassLoaderSearch.invoke(instrumentation, jarFile);
2465                     } catch (IllegalAccessException exception) {
2466                         throw new IllegalStateException("Cannot access java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch", exception);
2467                     } catch (InvocationTargetException exception) {
2468                         throw new IllegalStateException("Error invoking java.lang.instrument.Instrumentation#appendToBootstrapClassLoaderSearch", exception.getCause());
2469                     }
2470                 }
2471
2472                 /**
2473                  * {@inheritDoc}
2474                  */

2475                 public void appendToSystemClassLoaderSearch(Instrumentation instrumentation, JarFile jarFile) {
2476                     try {
2477                         appendToSystemClassLoaderSearch.invoke(instrumentation, jarFile);
2478                     } catch (IllegalAccessException exception) {
2479                         throw new IllegalStateException("Cannot access java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch", exception);
2480                     } catch (InvocationTargetException exception) {
2481                         throw new IllegalStateException("Error invoking java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch", exception.getCause());
2482                     }
2483                 }
2484             }
2485         }
2486
2487         /**
2488          * A representation of the target to which Java classes should be appended to.
2489          */

2490         public enum Target {
2491
2492             /**
2493              * Representation of the bootstrap class loader.
2494              */

2495             BOOTSTRAP(null) {
2496                 @Override
2497                 protected void inject(Instrumentation instrumentation, JarFile jarFile) {
2498                     DISPATCHER.appendToBootstrapClassLoaderSearch(instrumentation, jarFile);
2499                 }
2500             },
2501
2502             /**
2503              * Representation of the system class loader.
2504              */

2505             SYSTEM(ClassLoader.getSystemClassLoader()) {
2506                 @Override
2507                 protected void inject(Instrumentation instrumentation, JarFile jarFile) {
2508                     DISPATCHER.appendToSystemClassLoaderSearch(instrumentation, jarFile);
2509                 }
2510             };
2511
2512             /**
2513              * The class loader to load classes from.
2514              */

2515             private final ClassLoader classLoader;
2516
2517             /**
2518              * Creates a new injection target.
2519              *
2520              * @param classLoader The class loader to load classes from.
2521              */

2522             Target(ClassLoader classLoader) {
2523                 this.classLoader = classLoader;
2524             }
2525
2526             /**
2527              * Returns the class loader to load classes from.
2528              *
2529              * @return The class loader to load classes from.
2530              */

2531             protected ClassLoader getClassLoader() {
2532                 return classLoader;
2533             }
2534
2535             /**
2536              * Adds the given classes to the represented class loader.
2537              *
2538              * @param instrumentation The instrumentation instance to use.
2539              * @param jarFile         The jar file to append.
2540              */

2541             protected abstract void inject(Instrumentation instrumentation, JarFile jarFile);
2542         }
2543     }
2544 }
2545