• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

raphw / byte-buddy / #811

03 Nov 2025 10:41AM UTC coverage: 83.677% (-0.3%) from 84.023%
#811

push

raphw
Fix null handling.

0 of 1 new or added line in 1 file covered. (0.0%)

791 existing lines in 12 files now uncovered.

29814 of 35630 relevant lines covered (83.68%)

0.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.05
/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/loading/ClassLoadingStrategy.java
1
/*
2
 * Copyright 2014 - Present 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 net.bytebuddy.build.HashCodeAndEqualsPlugin;
19
import net.bytebuddy.description.type.TypeDescription;
20
import net.bytebuddy.utility.nullability.AlwaysNull;
21
import net.bytebuddy.utility.nullability.MaybeNull;
22

23
import java.io.File;
24
import java.lang.instrument.Instrumentation;
25
import java.security.ProtectionDomain;
26
import java.util.Map;
27
import java.util.concurrent.Callable;
28

29
/**
30
 * A strategy for loading a collection of types.
31
 *
32
 * @param <T> The least specific type of class loader this strategy can apply to.
33
 */
34
public interface ClassLoadingStrategy<T extends ClassLoader> {
35

36
    /**
37
     * A type-safe constant representing the bootstrap class loader which is represented by {@code null} within Java.
38
     */
39
    @AlwaysNull
40
    ClassLoader BOOTSTRAP_LOADER = null;
1✔
41

42
    /**
43
     * An undefined protection domain.
44
     */
45
    @AlwaysNull
46
    ProtectionDomain NO_PROTECTION_DOMAIN = null;
1✔
47

48
    /**
49
     * Loads a given collection of classes given their binary representation.
50
     *
51
     * @param classLoader The class loader to used for loading the classes.
52
     * @param types       Byte array representations of the types to be loaded mapped by their descriptions,
53
     *                    where an iteration order defines an order in which they are supposed to be loaded,
54
     *                    if relevant.
55
     * @return A collection of the loaded classes which will be initialized in the iteration order of the
56
     * returned collection.
57
     */
58
    Map<TypeDescription, Class<?>> load(@MaybeNull T classLoader, Map<TypeDescription, byte[]> types);
59

60
    /**
61
     * This class contains implementations of default class loading strategies.
62
     */
63
    enum Default implements Configurable<ClassLoader> {
1✔
64

65
        /**
66
         * This strategy creates a new {@link net.bytebuddy.dynamic.loading.ByteArrayClassLoader} with the given
67
         * class loader as its parent. The byte array class loader is aware of a any dynamically created type and can
68
         * natively load the given classes. This allows to load classes with cyclic load-time dependencies since the
69
         * byte array class loader is queried on each encountered unknown class. Due to the encapsulation of the
70
         * classes that were loaded by a byte array class loader, this strategy will lead to the unloading of these
71
         * classes once this class loader, its classes or any instances of these classes become unreachable.
72
         */
73
        WRAPPER(new WrappingDispatcher(ByteArrayClassLoader.PersistenceHandler.LATENT, WrappingDispatcher.PARENT_FIRST)),
1✔
74

75
        /**
76
         * The strategy is identical to {@link ClassLoadingStrategy.Default#WRAPPER} but exposes
77
         * the byte arrays that represent a class by {@link java.lang.ClassLoader#getResourceAsStream(String)}. For
78
         * this purpose, all class files are persisted as byte arrays withing the wrapping class loader.
79
         */
80
        WRAPPER_PERSISTENT(new WrappingDispatcher(ByteArrayClassLoader.PersistenceHandler.MANIFEST, WrappingDispatcher.PARENT_FIRST)),
1✔
81

82
        /**
83
         * <p>
84
         * The child-first class loading strategy is a modified version of the
85
         * {@link ClassLoadingStrategy.Default#WRAPPER} where the dynamic types are given
86
         * priority over any types of a parent class loader with the same name.
87
         * </p>
88
         * <p>
89
         * <b>Important</b>: This does <i>not</i> replace a type of the same name, but it makes the type invisible by
90
         * the reach of this class loader.
91
         * </p>
92
         */
93
        CHILD_FIRST(new WrappingDispatcher(ByteArrayClassLoader.PersistenceHandler.LATENT, WrappingDispatcher.CHILD_FIRST)),
1✔
94

95
        /**
96
         * The strategy is identical to {@link ClassLoadingStrategy.Default#CHILD_FIRST} but
97
         * exposes the byte arrays that represent a class by {@link java.lang.ClassLoader#getResourceAsStream(String)}.
98
         * For this purpose, all class files are persisted as byte arrays withing the wrapping class loader.
99
         */
100
        CHILD_FIRST_PERSISTENT(new WrappingDispatcher(ByteArrayClassLoader.PersistenceHandler.MANIFEST, WrappingDispatcher.CHILD_FIRST)),
1✔
101

102
        /**
103
         * <p>
104
         * This strategy does not create a new class loader but injects all classes into the given {@link java.lang.ClassLoader}
105
         * by reflective access. This prevents the loading of classes with cyclic load-time dependencies but avoids the
106
         * creation of an additional class loader. The advantage of this strategy is that the loaded classes will have
107
         * package-private access to other classes within their package of the class loader into which they are
108
         * injected what is not permitted when the wrapper class loader is used. This strategy is implemented using a
109
         * {@link net.bytebuddy.dynamic.loading.ClassInjector.UsingReflection}. Note that this strategy usually yields
110
         * a better runtime performance.
111
         * </p>
112
         * <p>
113
         * <b>Important</b>: Class injection requires access to JVM internal methods that are sealed by security managers and the
114
         * Java Platform module system. Since Java 11, access to these methods is no longer feasible unless those packages
115
         * are explicitly opened.
116
         * </p>
117
         * <p>
118
         * <b>Note</b>: This class loader does not define packages for injected classes by default. Therefore, calls to
119
         * {@link Class#getPackage()} might return {@code null}. Packages are only defined manually by a class loader prior to
120
         * Java 9.
121
         * </p>
122
         */
123
        INJECTION(new InjectionDispatcher());
1✔
124

125
        /**
126
         * The default behavior when attempting to load a type that was already loaded.
127
         */
128
        private static final boolean DEFAULT_FORBID_EXISTING = true;
129

130
        /**
131
         * The dispatcher to be used when loading a class.
132
         */
133
        private final Configurable<ClassLoader> dispatcher;
134

135
        /**
136
         * Creates a new default class loading strategy.
137
         *
138
         * @param dispatcher The dispatcher to be used when loading a class.
139
         */
140
        Default(Configurable<ClassLoader> dispatcher) {
1✔
141
            this.dispatcher = dispatcher;
1✔
142
        }
1✔
143

144
        /**
145
         * {@inheritDoc}
146
         */
147
        public Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader, Map<TypeDescription, byte[]> types) {
148
            return dispatcher.load(classLoader, types);
1✔
149
        }
150

151
        /**
152
         * {@inheritDoc}
153
         */
154
        public Configurable<ClassLoader> with(ProtectionDomain protectionDomain) {
155
            return dispatcher.with(protectionDomain);
1✔
156
        }
157

158
        /**
159
         * {@inheritDoc}
160
         */
161
        public Configurable<ClassLoader> with(PackageDefinitionStrategy packageDefinitionStrategy) {
162
            return dispatcher.with(packageDefinitionStrategy);
1✔
163
        }
164

165
        /**
166
         * {@inheritDoc}
167
         */
168
        public Configurable<ClassLoader> with(ClassLoaderDecorator.Factory classLoaderDecoratorFactory) {
UNCOV
169
            return dispatcher.with(classLoaderDecoratorFactory);
×
170
        }
171

172
        /**
173
         * {@inheritDoc}
174
         */
175
        public Configurable<ClassLoader> allowExistingTypes() {
176
            return dispatcher.allowExistingTypes();
1✔
177
        }
178

179
        /**
180
         * {@inheritDoc}
181
         */
182
        public Configurable<ClassLoader> opened() {
183
            return dispatcher.opened();
1✔
184
        }
185

186
        /**
187
         * <p>
188
         * A class loading strategy which applies a class loader injection while applying a given {@link java.security.ProtectionDomain} on class injection.
189
         * </p>
190
         * <p>
191
         * <b>Important</b>: Class injection requires access to JVM internal methods that are sealed by security managers and the
192
         * Java Platform module system. Since Java 11, access to these methods is no longer feasible unless those packages
193
         * are explicitly opened.
194
         * </p>
195
         */
196
        @HashCodeAndEqualsPlugin.Enhance
197
        protected static class InjectionDispatcher implements ClassLoadingStrategy.Configurable<ClassLoader> {
198

199
            /**
200
             * The protection domain to apply or {@code null} if no protection domain is set.
201
             */
202
            @MaybeNull
203
            @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
204
            private final ProtectionDomain protectionDomain;
205

206
            /**
207
             * The package definer to be used for querying information on package information.
208
             */
209
            private final PackageDefinitionStrategy packageDefinitionStrategy;
210

211
            /**
212
             * Determines if an exception should be thrown when attempting to load a type that already exists.
213
             */
214
            private final boolean forbidExisting;
215

216
            /**
217
             * Creates a new injection dispatcher.
218
             */
219
            protected InjectionDispatcher() {
220
                this(NO_PROTECTION_DOMAIN, PackageDefinitionStrategy.NoOp.INSTANCE, DEFAULT_FORBID_EXISTING);
1✔
221
            }
1✔
222

223
            /**
224
             * Creates a new injection dispatcher.
225
             *
226
             * @param protectionDomain          The protection domain to apply or {@code null} if no protection domain is set.
227
             * @param packageDefinitionStrategy The package definer to be used for querying information on package information.
228
             * @param forbidExisting            Determines if an exception should be thrown when attempting to load a type that already exists.
229
             */
230
            private InjectionDispatcher(@MaybeNull ProtectionDomain protectionDomain,
231
                                        PackageDefinitionStrategy packageDefinitionStrategy,
232
                                        boolean forbidExisting) {
1✔
233
                this.protectionDomain = protectionDomain;
1✔
234
                this.packageDefinitionStrategy = packageDefinitionStrategy;
1✔
235
                this.forbidExisting = forbidExisting;
1✔
236
            }
1✔
237

238
            /**
239
             * {@inheritDoc}
240
             */
241
            public Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader, Map<TypeDescription, byte[]> types) {
242
                if (classLoader == null) {
1✔
UNCOV
243
                    throw new IllegalArgumentException("Cannot inject classes into the bootstrap class loader");
×
244
                }
245
                return new ClassInjector.UsingReflection(classLoader,
1✔
246
                        protectionDomain,
247
                        packageDefinitionStrategy,
248
                        forbidExisting).inject(types);
1✔
249
            }
250

251
            /**
252
             * {@inheritDoc}
253
             */
254
            public Configurable<ClassLoader> with(ProtectionDomain protectionDomain) {
255
                return new InjectionDispatcher(protectionDomain, packageDefinitionStrategy, forbidExisting);
1✔
256
            }
257

258
            /**
259
             * {@inheritDoc}
260
             */
261
            public Configurable<ClassLoader> with(PackageDefinitionStrategy packageDefinitionStrategy) {
262
                return new InjectionDispatcher(protectionDomain, packageDefinitionStrategy, forbidExisting);
1✔
263
            }
264

265
            /**
266
             * {@inheritDoc}
267
             */
268
            public Configurable<ClassLoader> with(ClassLoaderDecorator.Factory classLoaderDecoratorFactory) {
269
                throw new UnsupportedOperationException("Cannot decorate a class loader when using injection");
×
270
            }
271

272
            /**
273
             * {@inheritDoc}
274
             */
275
            public Configurable<ClassLoader> allowExistingTypes() {
276
                return new InjectionDispatcher(protectionDomain, packageDefinitionStrategy, false);
1✔
277
            }
278

279
            /**
280
             * {@inheritDoc}
281
             */
282
            public Configurable<ClassLoader> opened() {
UNCOV
283
                return this;
×
284
            }
285
        }
286

287
        /**
288
         * A class loading strategy which creates a wrapping class loader while applying a given
289
         * {@link java.security.ProtectionDomain} on class loading.
290
         */
291
        @HashCodeAndEqualsPlugin.Enhance
292
        protected static class WrappingDispatcher implements ClassLoadingStrategy.Configurable<ClassLoader> {
293

294
            /**
295
             * Indicates that a child first loading strategy should be attempted.
296
             */
297
            private static final boolean CHILD_FIRST = true;
298

299
            /**
300
             * Indicates that a parent first loading strategy should be attempted.
301
             */
302
            private static final boolean PARENT_FIRST = false;
303

304
            /**
305
             * The protection domain to apply or {@code null} if no protection domain is set.
306
             */
307
            @MaybeNull
308
            @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
309
            private final ProtectionDomain protectionDomain;
310

311
            /**
312
             * The persistence handler to apply.
313
             */
314
            private final ByteArrayClassLoader.PersistenceHandler persistenceHandler;
315

316
            /**
317
             * The package definer to be used for querying information on package information.
318
             */
319
            private final PackageDefinitionStrategy packageDefinitionStrategy;
320

321
            /**
322
             * The class loader decorator factory to use.
323
             */
324
            private final ClassLoaderDecorator.Factory classLoaderDecoratorFactory;
325

326
            /**
327
             * {@code true} if the created class loader should apply child-first semantics.
328
             */
329
            private final boolean childFirst;
330

331
            /**
332
             * Determines if an exception should be thrown when attempting to load a type that already exists.
333
             */
334
            private final boolean forbidExisting;
335

336
            /**
337
             * {@code true} if the class loader should be sealed.
338
             */
339
            private final boolean sealed;
340

341
            /**
342
             * Creates a new wrapping dispatcher with a default protection domain and a default access control context.
343
             *
344
             * @param persistenceHandler The persistence handler to apply.
345
             * @param childFirst         {@code true} if the created class loader should apply child-first semantics.
346
             */
347
            protected WrappingDispatcher(ByteArrayClassLoader.PersistenceHandler persistenceHandler, boolean childFirst) {
348
                this(NO_PROTECTION_DOMAIN,
1✔
349
                        PackageDefinitionStrategy.Trivial.INSTANCE,
350
                        persistenceHandler,
351
                        ClassLoaderDecorator.Factory.NoOp.INSTANCE,
352
                        childFirst,
353
                        DEFAULT_FORBID_EXISTING,
354
                        true);
355
            }
1✔
356

357
            /**
358
             * Creates a new protection domain specific class loading wrapper.
359
             *
360
             * @param protectionDomain            The protection domain to apply or {@code null} if no protection domain is set.
361
             * @param packageDefinitionStrategy   The package definer to be used for querying information on package information.
362
             * @param persistenceHandler          The persistence handler to apply.
363
             * @param classLoaderDecoratorFactory The class loader decorator factory to use.
364
             * @param childFirst                  {@code true} if the created class loader should apply child-first semantics.
365
             * @param forbidExisting              Determines if an exception should be thrown when attempting to load a type that already exists.
366
             * @param sealed                      {@code true} if the class loader should be sealed.
367
             */
368
            private WrappingDispatcher(@MaybeNull ProtectionDomain protectionDomain,
369
                                       PackageDefinitionStrategy packageDefinitionStrategy,
370
                                       ByteArrayClassLoader.PersistenceHandler persistenceHandler,
371
                                       ClassLoaderDecorator.Factory classLoaderDecoratorFactory,
372
                                       boolean childFirst,
373
                                       boolean forbidExisting,
374
                                       boolean sealed) {
1✔
375
                this.protectionDomain = protectionDomain;
1✔
376
                this.packageDefinitionStrategy = packageDefinitionStrategy;
1✔
377
                this.persistenceHandler = persistenceHandler;
1✔
378
                this.classLoaderDecoratorFactory = classLoaderDecoratorFactory;
1✔
379
                this.childFirst = childFirst;
1✔
380
                this.forbidExisting = forbidExisting;
1✔
381
                this.sealed = sealed;
1✔
382
            }
1✔
383

384
            /**
385
             * {@inheritDoc}
386
             */
387
            public Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader, Map<TypeDescription, byte[]> types) {
388
                return childFirst
1✔
389
                        ? ByteArrayClassLoader.ChildFirst.load(classLoader, types, protectionDomain, persistenceHandler, packageDefinitionStrategy, classLoaderDecoratorFactory, forbidExisting, sealed)
1✔
390
                        : ByteArrayClassLoader.load(classLoader, types, protectionDomain, persistenceHandler, packageDefinitionStrategy, classLoaderDecoratorFactory, forbidExisting, sealed);
1✔
391
            }
392

393
            /**
394
             * {@inheritDoc}
395
             */
396
            public Configurable<ClassLoader> with(ProtectionDomain protectionDomain) {
397
                return new WrappingDispatcher(protectionDomain, packageDefinitionStrategy, persistenceHandler, classLoaderDecoratorFactory, childFirst, forbidExisting, sealed);
1✔
398
            }
399

400
            /**
401
             * {@inheritDoc}
402
             */
403
            public Configurable<ClassLoader> with(PackageDefinitionStrategy packageDefinitionStrategy) {
404
                return new WrappingDispatcher(protectionDomain, packageDefinitionStrategy, persistenceHandler, classLoaderDecoratorFactory, childFirst, forbidExisting, sealed);
1✔
405
            }
406

407
            /**
408
             * {@inheritDoc}
409
             */
410
            public Configurable<ClassLoader> with(ClassLoaderDecorator.Factory classLoaderDecoratorFactory) {
UNCOV
411
                return new WrappingDispatcher(protectionDomain, packageDefinitionStrategy, persistenceHandler, classLoaderDecoratorFactory, childFirst, forbidExisting, sealed);
×
412
            }
413

414
            /**
415
             * {@inheritDoc}
416
             */
417
            public Configurable<ClassLoader> allowExistingTypes() {
418
                return new WrappingDispatcher(protectionDomain, packageDefinitionStrategy, persistenceHandler, classLoaderDecoratorFactory, childFirst, false, sealed);
1✔
419
            }
420

421
            /**
422
             * {@inheritDoc}
423
             */
424
            public Configurable<ClassLoader> opened() {
425
                return new WrappingDispatcher(protectionDomain, packageDefinitionStrategy, persistenceHandler, classLoaderDecoratorFactory, childFirst, forbidExisting, false);
1✔
426
            }
427
        }
428
    }
429

430
    /**
431
     * A {@link ClassLoadingStrategy} that allows configuring the strategy's behavior.
432
     *
433
     * @param <S> The least specific type of class loader this strategy can apply to.
434
     */
435
    interface Configurable<S extends ClassLoader> extends ClassLoadingStrategy<S> {
436

437
        /**
438
         * Overrides the implicitly set default {@link java.security.ProtectionDomain} with an explicit one.
439
         *
440
         * @param protectionDomain The protection domain to apply or {@code null} if no protection domain is set.
441
         * @return This class loading strategy with an explicitly set {@link java.security.ProtectionDomain}.
442
         */
443
        Configurable<S> with(ProtectionDomain protectionDomain);
444

445
        /**
446
         * Defines the supplied package definition strategy to be used for defining packages.
447
         *
448
         * @param packageDefinitionStrategy The package definer to be used.
449
         * @return A version of this class loading strategy that applies the supplied package definition strategy.
450
         */
451
        Configurable<S> with(PackageDefinitionStrategy packageDefinitionStrategy);
452

453
        /**
454
         * Defines a factory that decorates a given class loader prior to class loading. Note that this cannot
455
         * be used with injection.
456
         *
457
         * @param classLoaderDecoratorFactory The class loader decorator factory to use.
458
         * @return A version of this class loading strategy that applies the supplied class loader decorator factory.
459
         */
460
        Configurable<S> with(ClassLoaderDecorator.Factory classLoaderDecoratorFactory);
461

462
        /**
463
         * Determines if this class loading strategy should not throw an exception when attempting to load a class that
464
         * was already loaded. In this case, the already loaded class is used instead of the generated class.
465
         *
466
         * @return A version of this class loading strategy that does not throw an exception when a class is already loaded.
467
         */
468
        Configurable<S> allowExistingTypes();
469

470
        /**
471
         * With an opened class loading strategy, it is assured that types can be added to the class loader, either by
472
         * indirect injection using this strategy or by creating a class loader that explicitly supports injection.
473
         *
474
         * @return A version of this class loading strategy that opens for future injections into a class loader.
475
         */
476
        Configurable<S> opened();
477
    }
478

479
    /**
480
     * A class loading strategy that uses a {@code java.lang.invoke.MethodHandles$Lookup} instance for defining types.
481
     * A lookup instance can define types only in the same class loader and in the same package as the type within which
482
     * it was created. The supplied lookup must have package privileges, i.e. it must not be a public lookup.
483
     */
484
    @HashCodeAndEqualsPlugin.Enhance
485
    class UsingLookup implements ClassLoadingStrategy<ClassLoader> {
486

487
        /**
488
         * The class injector to use.
489
         */
490
        private final ClassInjector classInjector;
491

492
        /**
493
         * Creates a new class loading strategy that uses a lookup type.
494
         *
495
         * @param classInjector The class injector to use.
496
         */
497
        protected UsingLookup(ClassInjector classInjector) {
1✔
498
            this.classInjector = classInjector;
1✔
499
        }
1✔
500

501
        /**
502
         * Creates a new class loading strategy that uses a {@code java.lang.invoke.MethodHandles$Lookup} instance.
503
         *
504
         * @param lookup The lookup instance to use for defining new types.
505
         * @return A suitable class loading strategy.
506
         */
507
        public static ClassLoadingStrategy<ClassLoader> of(Object lookup) {
508
            return new UsingLookup(ClassInjector.UsingLookup.of(lookup));
×
509
        }
510

511
        /**
512
         * Resolves a class loading strategy using a lookup if available on the current JVM. If the current JVM supports method handles
513
         * lookups, a lookup instance will be used. Alternatively, unsafe class definition is used, if supported. If neither strategy is
514
         * supported, an exception is thrown. A common use case would be calling this method as in
515
         * {@code ClassLoadingStrategy.UsingLookup.withFallback(MethodHandles::lookup)}. Note that the invocation of
516
         * {@code MethodHandles.lookup()} is call site sensitive such that it cannot be invoked within Byte Buddy what requires this
517
         * external invocation.
518
         *
519
         * @param lookup A resolver for a lookup instance if the current JVM allows for lookup-based class injection.
520
         * @return An appropriate class loading strategy for the current JVM that uses a method handles lookup if available.
521
         */
522
        public static ClassLoadingStrategy<ClassLoader> withFallback(Callable<?> lookup) {
523
            return withFallback(lookup, false);
1✔
524
        }
525

526
        /**
527
         * Resolves a class loading strategy using a lookup if available on the current JVM. If the current JVM supports method handles
528
         * lookups, a lookup instance will be used. Alternatively, unsafe class definition is used, if supported. If neither strategy is
529
         * supported, an exception is thrown. A common use case would be calling this method as in
530
         * {@code ClassLoadingStrategy.UsingLookup.withFallback(MethodHandles::lookup)}. Note that the invocation of
531
         * {@code MethodHandles.lookup()} is call site sensitive such that it cannot be invoked within Byte Buddy what requires this
532
         * external invocation.
533
         *
534
         * @param lookup  A resolver for a lookup instance if the current JVM allows for lookup-based class injection.
535
         * @param wrapper {@code true} if a {@link Default#WRAPPER} strategy should be used as a fallback in case that no injection strategy is available.
536
         * @return An appropriate class loading strategy for the current JVM that uses a method handles lookup if available.
537
         */
538
        public static ClassLoadingStrategy<ClassLoader> withFallback(Callable<?> lookup, boolean wrapper) {
539
            if (ClassInjector.UsingLookup.isAvailable()) {
1✔
540
                try {
UNCOV
541
                    return of(lookup.call());
×
UNCOV
542
                } catch (Exception exception) {
×
UNCOV
543
                    throw new IllegalStateException(exception);
×
544
                }
545
            } else if (ClassInjector.UsingUnsafe.isAvailable()) {
1✔
546
                return new ClassLoadingStrategy.ForUnsafeInjection();
1✔
UNCOV
547
            } else if (wrapper) {
×
UNCOV
548
                return Default.WRAPPER;
×
549
            } else {
UNCOV
550
                throw new IllegalStateException("Neither lookup or unsafe class injection is available");
×
551
            }
552
        }
553

554
        /**
555
         * {@inheritDoc}
556
         */
557
        public Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader, Map<TypeDescription, byte[]> types) {
558
            return classInjector.inject(types);
1✔
559
        }
560
    }
561

562
    /**
563
     * A class loading strategy which allows class injection into the bootstrap class loader if
564
     * appropriate.
565
     */
566
    @HashCodeAndEqualsPlugin.Enhance
567
    class ForBootstrapInjection implements ClassLoadingStrategy<ClassLoader> {
568

569
        /**
570
         * The instrumentation to use.
571
         */
572
        private final Instrumentation instrumentation;
573

574
        /**
575
         * The folder to save jar files in.
576
         */
577
        private final File folder;
578

579
        /**
580
         * Creates a new injector which is capable of injecting classes into the bootstrap class loader.
581
         *
582
         * @param instrumentation The instrumentation to use.
583
         * @param folder          The folder to save jar files in.
584
         */
585
        public ForBootstrapInjection(Instrumentation instrumentation, File folder) {
1✔
586
            this.instrumentation = instrumentation;
1✔
587
            this.folder = folder;
1✔
588
        }
1✔
589

590
        /**
591
         * {@inheritDoc}
592
         */
593
        public Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader, Map<TypeDescription, byte[]> types) {
594
            ClassInjector classInjector = classLoader == null
1✔
595
                    ? ClassInjector.UsingInstrumentation.of(folder, ClassInjector.UsingInstrumentation.Target.BOOTSTRAP, instrumentation)
1✔
596
                    : new ClassInjector.UsingReflection(classLoader);
597
            return classInjector.inject(types);
1✔
598
        }
599
    }
600

601
    /**
602
     * A class loading strategy that injects a class using {@code sun.misc.Unsafe} or {@code jdk.internal.misc.Unsafe}.
603
     */
604
    @HashCodeAndEqualsPlugin.Enhance
605
    class ForUnsafeInjection implements ClassLoadingStrategy<ClassLoader> {
606

607
        /**
608
         * The protection domain to use or {@code null} if no protection domain is set.
609
         */
610
        @MaybeNull
611
        @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
612
        private final ProtectionDomain protectionDomain;
613

614
        /**
615
         * Creates a new class loading strategy for unsafe injection with a default protection domain.
616
         */
617
        public ForUnsafeInjection() {
618
            this(NO_PROTECTION_DOMAIN);
1✔
619
        }
1✔
620

621
        /**
622
         * Creates a new class loading strategy for unsafe injection.
623
         *
624
         * @param protectionDomain The protection domain to use or {@code null} if no protection domain is set.
625
         */
626
        public ForUnsafeInjection(@MaybeNull ProtectionDomain protectionDomain) {
1✔
627
            this.protectionDomain = protectionDomain;
1✔
628
        }
1✔
629

630
        /**
631
         * {@inheritDoc}
632
         */
633
        public Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader, Map<TypeDescription, byte[]> types) {
634
            return new ClassInjector.UsingUnsafe(classLoader, protectionDomain).inject(types);
1✔
635
        }
636
    }
637

638
    /**
639
     * A class loading strategy that injects a class using JNA via the JNI <i>DefineClass</i> method. This strategy can
640
     * only be used if JNA is explicitly added as a dependency. Some JVM implementations might not support this strategy.
641
     */
642
    @HashCodeAndEqualsPlugin.Enhance
643
    class ForJnaInjection implements ClassLoadingStrategy<ClassLoader> {
644

645
        /**
646
         * The protection domain to use or {@code null} if no protection domain is set.
647
         */
648
        @MaybeNull
649
        @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
650
        private final ProtectionDomain protectionDomain;
651

652
        /**
653
         * Creates a new class loading strategy for JNA-based injection with a default protection domain.
654
         */
655
        public ForJnaInjection() {
656
            this(NO_PROTECTION_DOMAIN);
1✔
657
        }
1✔
658

659
        /**
660
         * Creates a new class loading strategy for JNA-based injection.
661
         *
662
         * @param protectionDomain The protection domain to use or {@code null} if no protection domain is set.
663
         */
664
        public ForJnaInjection(@MaybeNull ProtectionDomain protectionDomain) {
1✔
665
            this.protectionDomain = protectionDomain;
1✔
666
        }
1✔
667

668
        /**
669
         * {@inheritDoc}
670
         */
671
        public Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader, Map<TypeDescription, byte[]> types) {
672
            return new ClassInjector.UsingUnsafe(classLoader, protectionDomain).inject(types);
1✔
673
        }
674
    }
675
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc