• 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

77.96
/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/loading/ByteArrayClassLoader.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 edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19
import net.bytebuddy.ClassFileVersion;
20
import net.bytebuddy.build.AccessControllerPlugin;
21
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
22
import net.bytebuddy.description.type.TypeDescription;
23
import net.bytebuddy.utility.GraalImageCode;
24
import net.bytebuddy.utility.JavaModule;
25
import net.bytebuddy.utility.dispatcher.JavaDispatcher;
26
import net.bytebuddy.utility.nullability.AlwaysNull;
27
import net.bytebuddy.utility.nullability.MaybeNull;
28

29
import java.io.ByteArrayInputStream;
30
import java.io.IOException;
31
import java.io.InputStream;
32
import java.io.UnsupportedEncodingException;
33
import java.lang.reflect.InvocationTargetException;
34
import java.lang.reflect.Method;
35
import java.net.MalformedURLException;
36
import java.net.URI;
37
import java.net.URL;
38
import java.net.URLConnection;
39
import java.net.URLEncoder;
40
import java.net.URLStreamHandler;
41
import java.security.PrivilegedAction;
42
import java.security.ProtectionDomain;
43
import java.util.Enumeration;
44
import java.util.HashMap;
45
import java.util.LinkedHashMap;
46
import java.util.Map;
47
import java.util.NoSuchElementException;
48
import java.util.concurrent.ConcurrentHashMap;
49
import java.util.concurrent.ConcurrentMap;
50

51
/**
52
 * <p>
53
 * A {@link java.lang.ClassLoader} that is capable of loading explicitly defined classes. The class loader will free
54
 * any binary resources once a class that is defined by its binary data is loaded. This class loader is thread safe since
55
 * the class loading mechanics are only called from synchronized context.
56
 * </p>
57
 * <p>
58
 * <b>Note</b>: Instances of this class loader return URLs for their represented class loaders with the <i>bytebuddy</i> schema.
59
 * These URLs do not represent URIs as two classes with the same name yield identical URLs but might represents different byte
60
 * arrays.
61
 * </p>
62
 * <p>
63
 * <b>Note</b>: Any class and package definition is performed using the creator's {@code java.security.AccessControlContext}.
64
 * </p>
65
 */
66
public class ByteArrayClassLoader extends InjectionClassLoader {
67

68
    /**
69
     * The schema for URLs that represent a class file of byte array class loaders.
70
     */
71
    public static final String URL_SCHEMA = "bytebuddy";
72

73
    /**
74
     * Indicates that an array should be included from its first index. Improves the source code readability.
75
     */
76
    private static final int FROM_BEGINNING = 0;
77

78
    /**
79
     * Indicates that a URL does not exist to improve code readability.
80
     */
81
    @AlwaysNull
82
    private static final URL NO_URL = null;
1✔
83

84
    /**
85
     * A strategy for locating a package by name.
86
     */
87
    private static final PackageLookupStrategy PACKAGE_LOOKUP_STRATEGY = doPrivileged(PackageLookupStrategy.CreationAction.INSTANCE);
1✔
88

89
    /**
90
     * The synchronization engine for the executing JVM.
91
     */
92
    protected static final SynchronizationStrategy.Initializable SYNCHRONIZATION_STRATEGY = doPrivileged(SynchronizationStrategy.CreationAction.INSTANCE);
1✔
93

94
    /*
95
     * Register class loader as parallel capable if the current VM supports it.
96
     */
97
    static {
98
        doRegisterAsParallelCapable();
1✔
99
    }
1✔
100

101
    /**
102
     * Registers class loader as parallel capable if possible.
103
     */
104
    @SuppressFBWarnings(value = "DP_DO_INSIDE_DO_PRIVILEGED", justification = "Must be invoked from targeting class loader type.")
105
    private static void doRegisterAsParallelCapable() {
106
        try {
107
            Method method = ClassLoader.class.getDeclaredMethod("registerAsParallelCapable");
1✔
108
            method.setAccessible(true);
1✔
109
            method.invoke(null);
1✔
UNCOV
110
        } catch (Throwable ignored) {
×
111
            /* do nothing */
112
        }
1✔
113
    }
1✔
114

115
    /**
116
     * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
117
     *
118
     * @param action The action to execute from a privileged context.
119
     * @param <T>    The type of the action's resolved value.
120
     * @return The action's resolved value.
121
     */
122
    @AccessControllerPlugin.Enhance
123
    private static <T> T doPrivileged(PrivilegedAction<T> action) {
UNCOV
124
        return action.run();
×
125
    }
126

127
    /**
128
     * A mutable map of type names mapped to their binary representation.
129
     */
130
    protected final ConcurrentMap<String, byte[]> typeDefinitions;
131

132
    /**
133
     * The persistence handler of this class loader.
134
     */
135
    protected final PersistenceHandler persistenceHandler;
136

137
    /**
138
     * The protection domain to apply. Might be {@code null} when referencing the default protection domain.
139
     */
140
    @MaybeNull
141
    protected final ProtectionDomain protectionDomain;
142

143
    /**
144
     * The package definer to be queried for package definitions.
145
     */
146
    protected final PackageDefinitionStrategy packageDefinitionStrategy;
147

148
    /**
149
     * The class file transformer to apply on loaded classes.
150
     */
151
    protected final ClassFilePostProcessor classFilePostProcessor;
152

153
    /**
154
     * The access control context to use for loading classes or {@code null} if this is not supported on the current VM.
155
     */
156
    @MaybeNull
157
    protected final Object accessControlContext;
158

159
    /**
160
     * Creates a new class loader for a given definition of classes.
161
     *
162
     * @param parent          The {@link java.lang.ClassLoader} that is the parent of this class loader.
163
     * @param typeDefinitions A map of fully qualified class names pointing to their binary representations.
164
     */
165
    public ByteArrayClassLoader(@MaybeNull ClassLoader parent, Map<String, byte[]> typeDefinitions) {
166
        this(parent, true, typeDefinitions);
1✔
167
    }
1✔
168

169
    /**
170
     * Creates a new class loader for a given definition of classes.
171
     *
172
     * @param parent          The {@link java.lang.ClassLoader} that is the parent of this class loader.
173
     * @param sealed          {@code true} if this class loader is sealed.
174
     * @param typeDefinitions A map of fully qualified class names pointing to their binary representations.
175
     */
176
    public ByteArrayClassLoader(@MaybeNull ClassLoader parent, boolean sealed, Map<String, byte[]> typeDefinitions) {
177
        this(parent, sealed, typeDefinitions, PersistenceHandler.LATENT);
1✔
178
    }
1✔
179

180
    /**
181
     * Creates a new class loader for a given definition of classes.
182
     *
183
     * @param parent             The {@link java.lang.ClassLoader} that is the parent of this class loader.
184
     * @param typeDefinitions    A map of fully qualified class names pointing to their binary representations.
185
     * @param persistenceHandler The persistence handler of this class loader.
186
     */
187
    public ByteArrayClassLoader(@MaybeNull ClassLoader parent, Map<String, byte[]> typeDefinitions, PersistenceHandler persistenceHandler) {
188
        this(parent, true, typeDefinitions, persistenceHandler);
1✔
189
    }
1✔
190

191
    /**
192
     * Creates a new class loader for a given definition of classes.
193
     *
194
     * @param parent             The {@link java.lang.ClassLoader} that is the parent of this class loader.
195
     * @param sealed             {@code true} if this class loader is sealed.
196
     * @param typeDefinitions    A map of fully qualified class names pointing to their binary representations.
197
     * @param persistenceHandler The persistence handler of this class loader.
198
     */
199
    public ByteArrayClassLoader(@MaybeNull ClassLoader parent, boolean sealed, Map<String, byte[]> typeDefinitions, PersistenceHandler persistenceHandler) {
200
        this(parent, sealed, typeDefinitions, ClassLoadingStrategy.NO_PROTECTION_DOMAIN, persistenceHandler, PackageDefinitionStrategy.Trivial.INSTANCE);
1✔
201
    }
1✔
202

203
    /**
204
     * Creates a new class loader for a given definition of classes.
205
     *
206
     * @param parent                    The {@link java.lang.ClassLoader} that is the parent of this class loader.
207
     * @param typeDefinitions           A map of fully qualified class names pointing to their binary representations.
208
     * @param protectionDomain          The protection domain to apply where {@code null} references an implicit protection domain.
209
     * @param packageDefinitionStrategy The package definer to be queried for package definitions.
210
     * @param persistenceHandler        The persistence handler of this class loader.
211
     */
212
    public ByteArrayClassLoader(@MaybeNull ClassLoader parent,
213
                                Map<String, byte[]> typeDefinitions,
214
                                @MaybeNull ProtectionDomain protectionDomain,
215
                                PersistenceHandler persistenceHandler,
216
                                PackageDefinitionStrategy packageDefinitionStrategy) {
217
        this(parent, true, typeDefinitions, protectionDomain, persistenceHandler, packageDefinitionStrategy);
1✔
218
    }
1✔
219

220
    /**
221
     * Creates a new class loader for a given definition of classes.
222
     *
223
     * @param parent                    The {@link java.lang.ClassLoader} that is the parent of this class loader.
224
     * @param sealed                    {@code true} if this class loader is sealed.
225
     * @param typeDefinitions           A map of fully qualified class names pointing to their binary representations.
226
     * @param protectionDomain          The protection domain to apply where {@code null} references an implicit protection domain.
227
     * @param packageDefinitionStrategy The package definer to be queried for package definitions.
228
     * @param persistenceHandler        The persistence handler of this class loader.
229
     */
230
    public ByteArrayClassLoader(@MaybeNull ClassLoader parent,
231
                                boolean sealed,
232
                                Map<String, byte[]> typeDefinitions,
233
                                @MaybeNull ProtectionDomain protectionDomain,
234
                                PersistenceHandler persistenceHandler,
235
                                PackageDefinitionStrategy packageDefinitionStrategy) {
236
        this(parent, sealed, typeDefinitions, protectionDomain, persistenceHandler, packageDefinitionStrategy, ClassFilePostProcessor.NoOp.INSTANCE);
1✔
237
    }
1✔
238

239
    /**
240
     * Creates a new class loader for a given definition of classes.
241
     *
242
     * @param parent                    The {@link java.lang.ClassLoader} that is the parent of this class loader.
243
     * @param typeDefinitions           A map of fully qualified class names pointing to their binary representations.
244
     * @param protectionDomain          The protection domain to apply where {@code null} references an implicit protection domain.
245
     * @param packageDefinitionStrategy The package definer to be queried for package definitions.
246
     * @param persistenceHandler        The persistence handler of this class loader.
247
     * @param classFilePostProcessor    A post processor for class files to apply p
248
     */
249
    public ByteArrayClassLoader(@MaybeNull ClassLoader parent,
250
                                Map<String, byte[]> typeDefinitions,
251
                                @MaybeNull ProtectionDomain protectionDomain,
252
                                PersistenceHandler persistenceHandler,
253
                                PackageDefinitionStrategy packageDefinitionStrategy,
254
                                ClassFilePostProcessor classFilePostProcessor) {
UNCOV
255
        this(parent, true, typeDefinitions, protectionDomain, persistenceHandler, packageDefinitionStrategy, classFilePostProcessor);
×
UNCOV
256
    }
×
257

258
    /**
259
     * Creates a new class loader for a given definition of classes.
260
     *
261
     * @param parent                    The {@link java.lang.ClassLoader} that is the parent of this class loader.
262
     * @param sealed                    {@code true} if this class loader is sealed.
263
     * @param typeDefinitions           A map of fully qualified class names pointing to their binary representations.
264
     * @param protectionDomain          The protection domain to apply where {@code null} references an implicit protection domain.
265
     * @param packageDefinitionStrategy The package definer to be queried for package definitions.
266
     * @param persistenceHandler        The persistence handler of this class loader.
267
     * @param classFilePostProcessor    A post processor for class files to apply p
268
     */
269
    public ByteArrayClassLoader(@MaybeNull ClassLoader parent,
270
                                boolean sealed,
271
                                Map<String, byte[]> typeDefinitions,
272
                                @MaybeNull ProtectionDomain protectionDomain,
273
                                PersistenceHandler persistenceHandler,
274
                                PackageDefinitionStrategy packageDefinitionStrategy,
275
                                ClassFilePostProcessor classFilePostProcessor) {
276
        super(parent, sealed);
1✔
277
        this.typeDefinitions = new ConcurrentHashMap<String, byte[]>(typeDefinitions);
1✔
278
        this.protectionDomain = protectionDomain;
1✔
279
        this.persistenceHandler = persistenceHandler;
1✔
280
        this.packageDefinitionStrategy = packageDefinitionStrategy;
1✔
281
        this.classFilePostProcessor = classFilePostProcessor;
1✔
282
        accessControlContext = getContext();
1✔
283
    }
1✔
284

285
    /**
286
     * A proxy for {@code java.security.AccessController#getContext} that is activated if available.
287
     *
288
     * @return The current access control context or {@code null} if the current VM does not support it.
289
     */
290
    @MaybeNull
291
    @AccessControllerPlugin.Enhance
292
    private static Object getContext() {
UNCOV
293
        return null;
×
294
    }
295

296
    /**
297
     * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
298
     *
299
     * @param action  The action to execute from a privileged context.
300
     * @param context The access control context or {@code null} if the current VM does not support it.
301
     * @param <T>     The type of the action's resolved value.
302
     * @return The action's resolved value.
303
     */
304
    @AccessControllerPlugin.Enhance
305
    private static <T> T doPrivileged(PrivilegedAction<T> action, @MaybeNull @SuppressWarnings("unused") Object context) {
UNCOV
306
        return action.run();
×
307
    }
308

309
    /**
310
     * Resolves a method handle in the scope of the {@link ByteArrayClassLoader} class.
311
     *
312
     * @return A method handle for this class.
313
     * @throws Exception If the method handle facility is not supported by the current virtual machine.
314
     */
315
    private static Object methodHandle() throws Exception {
316
        return Class.forName("java.lang.invoke.MethodHandles").getMethod("lookup").invoke(null);
1✔
317
    }
318

319
    /**
320
     * Loads a given set of class descriptions and their binary representations.
321
     *
322
     * @param classLoader The parent class loader.
323
     * @param types       The unloaded types to be loaded.
324
     * @return A map of the given type descriptions pointing to their loaded representations.
325
     */
326
    public static Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader, Map<TypeDescription, byte[]> types) {
UNCOV
327
        return load(classLoader,
×
328
                types,
329
                ClassLoadingStrategy.NO_PROTECTION_DOMAIN,
330
                PersistenceHandler.LATENT,
331
                PackageDefinitionStrategy.Trivial.INSTANCE,
332
                false,
333
                true);
334
    }
335

336
    /**
337
     * Loads a given set of class descriptions and their binary representations.
338
     *
339
     * @param classLoader               The parent class loader.
340
     * @param types                     The unloaded types to be loaded.
341
     * @param protectionDomain          The protection domain to apply where {@code null} references an implicit protection domain.
342
     * @param persistenceHandler        The persistence handler of the created class loader.
343
     * @param packageDefinitionStrategy The package definer to be queried for package definitions.
344
     * @param forbidExisting            {@code true} if the class loading should throw an exception if a class was already loaded by a parent class loader.
345
     * @param sealed                    {@code true} if the class loader should be sealed.
346
     * @return A map of the given type descriptions pointing to their loaded representations.
347
     */
348
    public static Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader,
349
                                                      Map<TypeDescription, byte[]> types,
350
                                                      @MaybeNull ProtectionDomain protectionDomain,
351
                                                      PersistenceHandler persistenceHandler,
352
                                                      PackageDefinitionStrategy packageDefinitionStrategy,
353
                                                      boolean forbidExisting,
354
                                                      boolean sealed) {
355
        return load(classLoader,
1✔
356
                types,
357
                protectionDomain,
358
                persistenceHandler,
359
                packageDefinitionStrategy,
360
                ClassLoaderDecorator.Factory.NoOp.INSTANCE,
361
                forbidExisting,
362
                sealed);
363
    }
364

365
    /**
366
     * Loads a given set of class descriptions and their binary representations.
367
     *
368
     * @param classLoader                 The parent class loader.
369
     * @param types                       The unloaded types to be loaded.
370
     * @param protectionDomain            The protection domain to apply where {@code null} references an implicit protection domain.
371
     * @param persistenceHandler          The persistence handler of the created class loader.
372
     * @param packageDefinitionStrategy   The package definer to be queried for package definitions.
373
     * @param classLoaderDecoratorFactory The class loader decorator factory to use.
374
     * @param forbidExisting              {@code true} if the class loading should throw an exception if a class was already loaded by a parent class loader.
375
     * @param sealed                      {@code true} if the class loader should be sealed.
376
     * @return A map of the given type descriptions pointing to their loaded representations.
377
     */
378
    @SuppressFBWarnings(value = "DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED", justification = "Assuring privilege is explicit user responsibility.")
379
    public static Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader,
380
                                                      Map<TypeDescription, byte[]> types,
381
                                                      @MaybeNull ProtectionDomain protectionDomain,
382
                                                      PersistenceHandler persistenceHandler,
383
                                                      PackageDefinitionStrategy packageDefinitionStrategy,
384
                                                      ClassLoaderDecorator.Factory classLoaderDecoratorFactory,
385
                                                      boolean forbidExisting,
386
                                                      boolean sealed) {
387
        Map<String, byte[]> typeDefinitions = new HashMap<String, byte[]>();
1✔
388
        for (Map.Entry<TypeDescription, byte[]> entry : types.entrySet()) {
1✔
389
            typeDefinitions.put(entry.getKey().getName(), entry.getValue());
1✔
390
        }
1✔
391
        classLoader = new ByteArrayClassLoader(classLoader,
1✔
392
                sealed,
393
                typeDefinitions,
394
                protectionDomain,
395
                persistenceHandler,
396
                packageDefinitionStrategy,
397
                ClassFilePostProcessor.NoOp.INSTANCE);
398
        ClassLoaderDecorator classLoaderDecorator = classLoaderDecoratorFactory.make(classLoader, typeDefinitions);
1✔
399
        Map<TypeDescription, Class<?>> result = new LinkedHashMap<TypeDescription, Class<?>>();
1✔
400
        for (TypeDescription typeDescription : types.keySet()) {
1✔
401
            if (classLoaderDecorator.isSkipped(typeDescription)) {
1✔
UNCOV
402
                continue;
×
403
            }
404
            try {
405
                ClassLoader currentClassLoader = classLoaderDecorator.apply(typeDescription);
1✔
406
                Class<?> type = Class.forName(typeDescription.getName(), false, currentClassLoader);
1✔
407
                if (!GraalImageCode.getCurrent().isNativeImageExecution() && forbidExisting && type.getClassLoader() != currentClassLoader) {
1✔
408
                    throw new IllegalStateException("Class already loaded: " + type);
1✔
409
                }
410
                result.put(typeDescription, type);
1✔
UNCOV
411
            } catch (ClassNotFoundException exception) {
×
UNCOV
412
                throw new IllegalStateException("Cannot load class " + typeDescription, exception);
×
413
            }
1✔
414
        }
1✔
415
        return result;
1✔
416
    }
417

418
    @Override
419
    protected Map<String, Class<?>> doDefineClasses(Map<String, byte[]> typeDefinitions) throws ClassNotFoundException {
420
        Map<String, byte[]> previous = new HashMap<String, byte[]>();
1✔
421
        for (Map.Entry<String, byte[]> entry : typeDefinitions.entrySet()) {
1✔
422
            previous.put(entry.getKey(), this.typeDefinitions.putIfAbsent(entry.getKey(), entry.getValue()));
1✔
423
        }
1✔
424
        try {
425
            Map<String, Class<?>> types = new LinkedHashMap<String, Class<?>>();
1✔
426
            for (String name : typeDefinitions.keySet()) {
1✔
427
                synchronized (SYNCHRONIZATION_STRATEGY.initialize().getClassLoadingLock(this, name)) {
1✔
428
                    types.put(name, loadClass(name));
1✔
429
                }
1✔
430
            }
1✔
431
            return types;
1✔
432
        } finally {
433
            for (Map.Entry<String, byte[]> entry : previous.entrySet()) {
1✔
434
                if (entry.getValue() == null) {
1✔
435
                    persistenceHandler.release(entry.getKey(), this.typeDefinitions);
1✔
436
                } else {
437
                    this.typeDefinitions.put(entry.getKey(), entry.getValue());
1✔
438
                }
439
            }
1✔
440
        }
441
    }
442

443
    /**
444
     * {@inheritDoc}
445
     */
446
    protected Class<?> findClass(String name) throws ClassNotFoundException {
447
        byte[] binaryRepresentation = persistenceHandler.lookup(name, typeDefinitions);
1✔
448
        if (binaryRepresentation == null) {
1✔
449
            throw new ClassNotFoundException(name);
1✔
450
        } else {
451
            return doPrivileged(new ClassDefinitionAction(name, classFilePostProcessor.transform(this,
1✔
452
                    name,
453
                    protectionDomain,
454
                    binaryRepresentation)), accessControlContext);
455
        }
456
    }
457

458
    /**
459
     * {@inheritDoc}
460
     */
461
    @MaybeNull
462
    protected URL findResource(String name) {
463
        return persistenceHandler.url(name, typeDefinitions);
1✔
464
    }
465

466
    /**
467
     * {@inheritDoc}
468
     */
469
    protected Enumeration<URL> findResources(String name) {
470
        URL url = persistenceHandler.url(name, typeDefinitions);
1✔
471
        return url == null
1✔
472
                ? EmptyEnumeration.INSTANCE
473
                : new SingletonEnumeration(url);
474
    }
475

476
    /**
477
     * Returns the package for a given name.
478
     *
479
     * @param name The name of the package.
480
     * @return A suitable package or {@code null} if no such package exists.
481
     */
482
    @MaybeNull
483
    @SuppressWarnings("deprecation")
484
    private Package doGetPackage(String name) {
485
        return getPackage(name);
1✔
486
    }
487

488
    /**
489
     * An engine for receiving a <i>class loading lock</i> when loading a class.
490
     */
491
    protected interface SynchronizationStrategy {
492

493
        /**
494
         * Receives the class loading lock.
495
         *
496
         * @param name        The name of the class being loaded.
497
         * @param classLoader The class loader loading the class.
498
         * @return The corresponding class loading lock.
499
         */
500
        Object getClassLoadingLock(ByteArrayClassLoader classLoader, String name);
501

502
        /**
503
         * An uninitialized synchronization strategy.
504
         */
505
        interface Initializable {
506

507
            /**
508
             * Initializes this synchronization strategy.
509
             *
510
             * @return The synchronization strategy to use.
511
             */
512
            SynchronizationStrategy initialize();
513
        }
514

515
        /**
516
         * A creation action for a synchronization strategy.
517
         */
518
        enum CreationAction implements PrivilegedAction<Initializable> {
1✔
519

520
            /**
521
             * The singleton instance.
522
             */
523
            INSTANCE;
1✔
524

525
            /**
526
             * {@inheritDoc}
527
             */
528
            @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback.")
529
            public Initializable run() {
530
                try {
531
                    try {
532
                        Class<?> methodType = Class.forName("java.lang.invoke.MethodType"), methodHandle = Class.forName("java.lang.invoke.MethodHandle");
1✔
533
                        return new ForJava8CapableVm(Class.forName("java.lang.invoke.MethodHandles$Lookup")
1✔
534
                                .getMethod("findVirtual", Class.class, String.class, methodType)
1✔
535
                                .invoke(ByteArrayClassLoader.methodHandle(), ClassLoader.class, "getClassLoadingLock", methodType.getMethod("methodType",
1✔
536
                                        Class.class,
537
                                        Class[].class).invoke(null, Object.class, new Class<?>[]{String.class})),
1✔
538
                                methodHandle.getMethod("bindTo", Object.class),
1✔
539
                                methodHandle.getMethod("invokeWithArguments", Object[].class));
1✔
UNCOV
540
                    } catch (Exception ignored) {
×
541
                        // On the bootstrap class loader, a lookup instance cannot be located reflectively. To avoid issuing a warning for accessing
542
                        // a protected method from outside of a class that is caused if the module system does not offer accessing the method.
UNCOV
543
                        return ClassFileVersion.ofThisVm(ClassFileVersion.JAVA_V5).isAtLeast(ClassFileVersion.JAVA_V9) && ByteArrayClassLoader.class.getClassLoader() == null
×
544
                                ? SynchronizationStrategy.ForLegacyVm.INSTANCE
UNCOV
545
                                : new ForJava7CapableVm(ClassLoader.class.getDeclaredMethod("getClassLoadingLock", String.class));
×
546
                    }
UNCOV
547
                } catch (Exception ignored) {
×
UNCOV
548
                    return SynchronizationStrategy.ForLegacyVm.INSTANCE;
×
549
                }
550
            }
551
        }
552

553
        /**
554
         * A synchronization engine for a VM that is not aware of parallel-capable class loaders.
555
         */
556
        enum ForLegacyVm implements SynchronizationStrategy, Initializable {
1✔
557

558
            /**
559
             * The singleton instance.
560
             */
561
            INSTANCE;
1✔
562

563
            /**
564
             * {@inheritDoc}
565
             */
566
            public Object getClassLoadingLock(ByteArrayClassLoader classLoader, String name) {
567
                return classLoader;
1✔
568
            }
569

570
            /**
571
             * {@inheritDoc}
572
             */
573
            public SynchronizationStrategy initialize() {
574
                return this;
1✔
575
            }
576
        }
577

578
        /**
579
         * A synchronization engine for a VM that is aware of parallel-capable class loaders.
580
         */
581
        @HashCodeAndEqualsPlugin.Enhance
582
        class ForJava7CapableVm implements SynchronizationStrategy, Initializable {
583

584
            /**
585
             * The {@code ClassLoader#getClassLoadingLock(String)} method.
586
             */
587
            private final Method method;
588

589
            /**
590
             * Creates a new synchronization strategy.
591
             *
592
             * @param method The {@code ClassLoader#getClassLoadingLock(String)} method.
593
             */
UNCOV
594
            protected ForJava7CapableVm(Method method) {
×
UNCOV
595
                this.method = method;
×
UNCOV
596
            }
×
597

598
            /**
599
             * {@inheritDoc}
600
             */
601
            public Object getClassLoadingLock(ByteArrayClassLoader classLoader, String name) {
602
                try {
UNCOV
603
                    return method.invoke(classLoader, name);
×
UNCOV
604
                } catch (IllegalAccessException exception) {
×
UNCOV
605
                    throw new IllegalStateException(exception);
×
UNCOV
606
                } catch (InvocationTargetException exception) {
×
UNCOV
607
                    throw new IllegalStateException(exception.getTargetException());
×
608
                }
609
            }
610

611
            /**
612
             * {@inheritDoc}
613
             */
614
            @SuppressFBWarnings(value = "DP_DO_INSIDE_DO_PRIVILEGED", justification = "Assuring privilege is explicit user responsibility.")
615
            public SynchronizationStrategy initialize() {
616
                try {
UNCOV
617
                    method.setAccessible(true);
×
618
                    return this;
×
619
                } catch (Exception ignored) {
×
620
                    return ForLegacyVm.INSTANCE;
×
621
                }
622
            }
623
        }
624

625
        /**
626
         * A synchronization engine for a VM that is aware of parallel-capable class loaders using method handles to respect module boundaries.
627
         */
628
        @HashCodeAndEqualsPlugin.Enhance
629
        class ForJava8CapableVm implements SynchronizationStrategy, Initializable {
630

631
            /**
632
             * The {@code java.lang.invoke.MethodHandle} to use.
633
             */
634
            private final Object methodHandle;
635

636
            /**
637
             * The {@code java.lang.invoke.MethodHandle#bindTo(Object)} method.
638
             */
639
            private final Method bindTo;
640

641
            /**
642
             * The {@code java.lang.invoke.MethodHandle#invokeWithArguments(Object[])} method.
643
             */
644
            private final Method invokeWithArguments;
645

646
            /**
647
             * Creates a new synchronization strategy.
648
             *
649
             * @param methodHandle        The {@code java.lang.invoke.MethodHandle} to use.
650
             * @param bindTo              The {@code java.lang.invoke.MethodHandle#bindTo(Object)} method.
651
             * @param invokeWithArguments The {@code java.lang.invoke.MethodHandle#invokeWithArguments(Object[])} method.
652
             */
653
            protected ForJava8CapableVm(Object methodHandle, Method bindTo, Method invokeWithArguments) {
1✔
654
                this.methodHandle = methodHandle;
1✔
655
                this.bindTo = bindTo;
1✔
656
                this.invokeWithArguments = invokeWithArguments;
1✔
657
            }
1✔
658

659
            /**
660
             * {@inheritDoc}
661
             */
662
            public SynchronizationStrategy initialize() {
663
                return this;
1✔
664
            }
665

666
            /**
667
             * {@inheritDoc}
668
             */
669
            public Object getClassLoadingLock(ByteArrayClassLoader classLoader, String name) {
670
                try {
671
                    return invokeWithArguments.invoke(bindTo.invoke(methodHandle, classLoader), (Object) new Object[]{name});
1✔
UNCOV
672
                } catch (IllegalAccessException exception) {
×
UNCOV
673
                    throw new IllegalStateException(exception);
×
UNCOV
674
                } catch (InvocationTargetException exception) {
×
UNCOV
675
                    throw new IllegalStateException(exception.getTargetException());
×
676
                }
677
            }
678
        }
679
    }
680

681
    /**
682
     * An action for defining a located class that is not yet loaded.
683
     */
684
    @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
685
    protected class ClassDefinitionAction implements PrivilegedAction<Class<?>> {
686

687
        /**
688
         * The binary name of the class to define.
689
         */
690
        private final String name;
691

692
        /**
693
         * The binary representation of the class to be loaded.
694
         */
695
        private final byte[] binaryRepresentation;
696

697
        /**
698
         * Creates a new class definition action.
699
         *
700
         * @param name                 The binary name of the class to define.
701
         * @param binaryRepresentation The binary representation of the class to be loaded.
702
         */
703
        protected ClassDefinitionAction(String name, byte[] binaryRepresentation) {
1✔
704
            this.name = name;
1✔
705
            this.binaryRepresentation = binaryRepresentation;
1✔
706
        }
1✔
707

708
        /**
709
         * {@inheritDoc}
710
         */
711
        public Class<?> run() {
712
            int packageIndex = name.lastIndexOf('.');
1✔
713
            if (packageIndex != -1) {
1✔
714
                String packageName = name.substring(0, packageIndex);
1✔
715
                PackageDefinitionStrategy.Definition definition = packageDefinitionStrategy.define(ByteArrayClassLoader.this, packageName, name);
1✔
716
                if (definition.isDefined()) {
1✔
717
                    Package definedPackage = PACKAGE_LOOKUP_STRATEGY.apply(ByteArrayClassLoader.this, packageName);
1✔
718
                    if (definedPackage == null) {
1✔
719
                        definePackage(packageName,
1✔
720
                                definition.getSpecificationTitle(),
1✔
721
                                definition.getSpecificationVersion(),
1✔
722
                                definition.getSpecificationVendor(),
1✔
723
                                definition.getImplementationTitle(),
1✔
724
                                definition.getImplementationVersion(),
1✔
725
                                definition.getImplementationVendor(),
1✔
726
                                definition.getSealBase());
1✔
727
                    } else if (!definition.isCompatibleTo(definedPackage)) {
1✔
UNCOV
728
                        throw new SecurityException("Sealing violation for package " + packageName);
×
729
                    }
730
                }
731
            }
732
            return defineClass(name, binaryRepresentation, FROM_BEGINNING, binaryRepresentation.length, protectionDomain);
1✔
733
        }
734
    }
735

736
    /**
737
     * A package lookup strategy for locating a package by name.
738
     */
739
    protected interface PackageLookupStrategy {
740

741
        /**
742
         * Returns a package for a given byte array class loader and a name.
743
         *
744
         * @param classLoader The class loader to locate a package for.
745
         * @param name        The name of the package.
746
         * @return A suitable package or {@code null} if no such package exists.
747
         */
748
        @MaybeNull
749
        Package apply(ByteArrayClassLoader classLoader, String name);
750

751
        /**
752
         * A creation action for a package lookup strategy.
753
         */
754
        enum CreationAction implements PrivilegedAction<PackageLookupStrategy> {
1✔
755

756
            /**
757
             * The singleton instance.
758
             */
759
            INSTANCE;
1✔
760

761
            /**
762
             * {@inheritDoc}
763
             */
764
            @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Exception should not be rethrown but trigger a fallback.")
765
            public PackageLookupStrategy run() {
766
                if (JavaModule.isSupported()) { // Avoid accidental lookup of method with same name in Java 8 J9 VM.
1✔
767
                    try {
UNCOV
768
                        return new PackageLookupStrategy.ForJava9CapableVm(ClassLoader.class.getMethod("getDefinedPackage", String.class));
×
UNCOV
769
                    } catch (Exception ignored) {
×
UNCOV
770
                        return PackageLookupStrategy.ForLegacyVm.INSTANCE;
×
771
                    }
772
                } else {
773
                    return PackageLookupStrategy.ForLegacyVm.INSTANCE;
1✔
774
                }
775
            }
776
        }
777

778
        /**
779
         * A package lookup strategy for a VM prior to Java 9.
780
         */
781
        enum ForLegacyVm implements PackageLookupStrategy {
1✔
782

783
            /**
784
             * The singleton instance.
785
             */
786
            INSTANCE;
1✔
787

788
            /**
789
             * {@inheritDoc}
790
             */
791
            @MaybeNull
792
            public Package apply(ByteArrayClassLoader classLoader, String name) {
793
                return classLoader.doGetPackage(name);
1✔
794
            }
795
        }
796

797
        /**
798
         * A package lookup strategy for Java 9 or newer.
799
         */
800
        @HashCodeAndEqualsPlugin.Enhance
801
        class ForJava9CapableVm implements PackageLookupStrategy {
802

803
            /**
804
             * The {@code java.lang.ClassLoader#getDefinedPackage(String)} method.
805
             */
806
            private final Method getDefinedPackage;
807

808
            /**
809
             * Creates a new package lookup strategy for a modern VM.
810
             *
811
             * @param getDefinedPackage The {@code java.lang.ClassLoader#getDefinedPackage(String)} method.
812
             */
UNCOV
813
            protected ForJava9CapableVm(Method getDefinedPackage) {
×
UNCOV
814
                this.getDefinedPackage = getDefinedPackage;
×
UNCOV
815
            }
×
816

817
            /**
818
             * {@inheritDoc}
819
             */
820
            @MaybeNull
821
            public Package apply(ByteArrayClassLoader classLoader, String name) {
822
                try {
UNCOV
823
                    return (Package) getDefinedPackage.invoke(classLoader, name);
×
UNCOV
824
                } catch (IllegalAccessException exception) {
×
UNCOV
825
                    throw new IllegalStateException(exception);
×
UNCOV
826
                } catch (InvocationTargetException exception) {
×
UNCOV
827
                    throw new IllegalStateException(exception.getTargetException());
×
828
                }
829
            }
830
        }
831
    }
832

833
    /**
834
     * A persistence handler decides on whether the byte array that represents a loaded class is exposed by
835
     * the {@link java.lang.ClassLoader#getResourceAsStream(String)} method.
836
     */
837
    public enum PersistenceHandler {
1✔
838

839
        /**
840
         * The manifest persistence handler retains all class file representations and makes them accessible.
841
         */
842
        MANIFEST(true) {
1✔
843
            @Override
844
            protected byte[] lookup(String name, ConcurrentMap<String, byte[]> typeDefinitions) {
845
                return typeDefinitions.get(name);
1✔
846
            }
847

848
            @Override
849
            protected URL url(String resourceName, ConcurrentMap<String, byte[]> typeDefinitions) {
850
                if (!resourceName.endsWith(CLASS_FILE_SUFFIX)) {
1✔
851
                    return NO_URL;
×
852
                } else if (resourceName.startsWith("/")) {
1✔
853
                    resourceName = resourceName.substring(1);
1✔
854
                }
855
                String typeName = resourceName.replace('/', '.').substring(FROM_BEGINNING, resourceName.length() - CLASS_FILE_SUFFIX.length());
1✔
856
                byte[] binaryRepresentation = typeDefinitions.get(typeName);
1✔
857
                return binaryRepresentation == null
1✔
858
                        ? NO_URL
1✔
859
                        : doPrivileged(new UrlDefinitionAction(resourceName, binaryRepresentation));
1✔
860
            }
861

862
            @Override
863
            protected void release(String name, ConcurrentMap<String, byte[]> typeDefinitions) {
864
                /* do nothing */
865
            }
1✔
866
        },
867

868
        /**
869
         * The latent persistence handler hides all class file representations and does not make them accessible
870
         * even before they are loaded.
871
         */
872
        LATENT(false) {
1✔
873
            @Override
874
            protected byte[] lookup(String name, ConcurrentMap<String, byte[]> typeDefinitions) {
875
                return typeDefinitions.remove(name);
1✔
876
            }
877

878
            @Override
879
            protected URL url(String resourceName, ConcurrentMap<String, byte[]> typeDefinitions) {
880
                return NO_URL;
1✔
881
            }
882

883
            @Override
884
            protected void release(String name, ConcurrentMap<String, byte[]> typeDefinitions) {
885
                typeDefinitions.remove(name);
1✔
886
            }
1✔
887
        };
888

889
        /**
890
         * The suffix of files in the Java class file format.
891
         */
892
        private static final String CLASS_FILE_SUFFIX = ".class";
893

894
        /**
895
         * {@code true} if this persistence handler represents manifest class file storage.
896
         */
897
        private final boolean manifest;
898

899
        /**
900
         * Creates a new persistence handler.
901
         *
902
         * @param manifest {@code true} if this persistence handler represents manifest class file storage.
903
         */
904
        PersistenceHandler(boolean manifest) {
1✔
905
            this.manifest = manifest;
1✔
906
        }
1✔
907

908
        /**
909
         * Checks if this persistence handler represents manifest class file storage.
910
         *
911
         * @return {@code true} if this persistence handler represents manifest class file storage.
912
         */
913
        public boolean isManifest() {
914
            return manifest;
1✔
915
        }
916

917
        /**
918
         * Performs a lookup of a class file by its name.
919
         *
920
         * @param name            The name of the class to be loaded.
921
         * @param typeDefinitions A map of fully qualified class names pointing to their binary representations.
922
         * @return The byte array representing the requested class or {@code null} if no such class is known.
923
         */
924
        @MaybeNull
925
        protected abstract byte[] lookup(String name, ConcurrentMap<String, byte[]> typeDefinitions);
926

927
        /**
928
         * Returns a URL representing a class file.
929
         *
930
         * @param resourceName    The name of the requested resource.
931
         * @param typeDefinitions A mapping of byte arrays by their type names.
932
         * @return A URL representing the type definition or {@code null} if the requested resource does not represent a class file.
933
         */
934
        @MaybeNull
935
        protected abstract URL url(String resourceName, ConcurrentMap<String, byte[]> typeDefinitions);
936

937
        /**
938
         * Removes the binary representation of the supplied type if this class loader is latent.
939
         *
940
         * @param name            The name of the type.
941
         * @param typeDefinitions A mapping of byte arrays by their type names.
942
         */
943
        protected abstract void release(String name, ConcurrentMap<String, byte[]> typeDefinitions);
944

945
        /**
946
         * An action to define a URL that represents a class file.
947
         */
948
        @HashCodeAndEqualsPlugin.Enhance
949
        protected static class UrlDefinitionAction implements PrivilegedAction<URL> {
950

951
            /**
952
             * A dispatcher for creating URLs.
953
             */
954
            private static final Dispatcher DISPATCHER = doPrivileged(JavaDispatcher.of(Dispatcher.class));
1✔
955

956
            /**
957
             * The URL's encoding character set.
958
             */
959
            private static final String ENCODING = "UTF-8";
960

961
            /**
962
             * A value to define a standard port as Byte Buddy's URLs do not represent a port.
963
             */
964
            private static final int NO_PORT = -1;
965

966
            /**
967
             * Indicates that Byte Buddy's URLs do not have a file segment.
968
             */
969
            private static final String NO_FILE = "";
970

971
            /**
972
             * The name of the type that this URL represents.
973
             */
974
            private final String typeName;
975

976
            /**
977
             * The binary representation of the type's class file.
978
             */
979
            private final byte[] binaryRepresentation;
980

981
            /**
982
             * Creates a new URL definition action.
983
             *
984
             * @param typeName             The name of the type that this URL represents.
985
             * @param binaryRepresentation The binary representation of the type's class file.
986
             */
987
            protected UrlDefinitionAction(String typeName, byte[] binaryRepresentation) {
1✔
988
                this.typeName = typeName;
1✔
989
                this.binaryRepresentation = binaryRepresentation;
1✔
990
            }
1✔
991

992
            /**
993
             * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
994
             *
995
             * @param action The action to execute from a privileged context.
996
             * @param <T>    The type of the action's resolved value.
997
             * @return The action's resolved value.
998
             */
999
            @AccessControllerPlugin.Enhance
1000
            private static <T> T doPrivileged(PrivilegedAction<T> action) {
UNCOV
1001
                return action.run();
×
1002
            }
1003

1004
            /**
1005
             * {@inheritDoc}
1006
             */
1007
            public URL run() {
1008
                try {
1009
                    String path = URLEncoder.encode(typeName.replace('.', '/'), ENCODING);
1✔
1010
                    URLStreamHandler handler = new ByteArrayUrlStreamHandler(binaryRepresentation);
1✔
1011
                    URL url = DISPATCHER.of(URI.create(URL_SCHEMA + "://" + path), handler);
1✔
1012
                    return url == null
1✔
1013
                            ? DISPATCHER.make(URL_SCHEMA, path, NO_PORT, NO_FILE, handler)
1✔
1014
                            : url;
UNCOV
1015
                } catch (MalformedURLException exception) {
×
UNCOV
1016
                    throw new IllegalStateException("Cannot create URL for " + typeName, exception);
×
UNCOV
1017
                } catch (UnsupportedEncodingException exception) {
×
UNCOV
1018
                    throw new IllegalStateException("Could not find encoding: " + ENCODING, exception);
×
1019
                }
1020
            }
1021

1022
            /**
1023
             * A stream handler that returns the given binary representation.
1024
             */
1025
            @HashCodeAndEqualsPlugin.Enhance
1026
            protected static class ByteArrayUrlStreamHandler extends URLStreamHandler {
1027

1028
                /**
1029
                 * The binary representation of a type's class file.
1030
                 */
1031
                private final byte[] binaryRepresentation;
1032

1033
                /**
1034
                 * Creates a new byte array URL stream handler.
1035
                 *
1036
                 * @param binaryRepresentation The binary representation of a type's class file.
1037
                 */
1038
                protected ByteArrayUrlStreamHandler(byte[] binaryRepresentation) {
1✔
1039
                    this.binaryRepresentation = binaryRepresentation;
1✔
1040
                }
1✔
1041

1042
                /**
1043
                 * {@inheritDoc}
1044
                 */
1045
                protected URLConnection openConnection(URL url) {
1046
                    return new ByteArrayUrlConnection(url, new ByteArrayInputStream(binaryRepresentation));
1✔
1047
                }
1048

1049
                /**
1050
                 * A URL connection for a given byte array.
1051
                 */
1052
                protected static class ByteArrayUrlConnection extends URLConnection {
1053

1054
                    /**
1055
                     * The input stream to return for this connection.
1056
                     */
1057
                    private final InputStream inputStream;
1058

1059
                    /**
1060
                     * Creates a new byte array URL connection.
1061
                     *
1062
                     * @param url         The URL that this connection represents.
1063
                     * @param inputStream The input stream to return from this connection.
1064
                     */
1065
                    protected ByteArrayUrlConnection(URL url, InputStream inputStream) {
1066
                        super(url);
1✔
1067
                        this.inputStream = inputStream;
1✔
1068
                    }
1✔
1069

1070
                    /**
1071
                     * {@inheritDoc}
1072
                     */
1073
                    public void connect() {
1074
                        connected = true;
1✔
1075
                    }
1✔
1076

1077
                    /**
1078
                     * {@inheritDoc}
1079
                     */
1080
                    public InputStream getInputStream() {
1081
                        connect(); // Mimics the semantics of an actual URL connection.
1✔
1082
                        return inputStream;
1✔
1083
                    }
1084
                }
1085
            }
1086

1087
            /**
1088
             * A dispatcher for interacting with {@link URL}.
1089
             */
1090
            @JavaDispatcher.Proxied("java.net.URL")
1091
            protected interface Dispatcher {
1092

1093
                /**
1094
                 * Creates a {@link URL}.
1095
                 *
1096
                 * @param protocol The URL's protocol.
1097
                 * @param host     The host on the URL.
1098
                 * @param port     The port on the URL or a negative value if no port is defined.
1099
                 * @param file     The file on the URL.
1100
                 * @param handler  The stream handler to use.
1101
                 * @return An appropriate URL.
1102
                 * @throws MalformedURLException If the supplied URL is malformed.
1103
                 */
1104
                @JavaDispatcher.IsConstructor
1105
                URL make(String protocol, String host, int port, String file, URLStreamHandler handler) throws MalformedURLException;
1106

1107
                /**
1108
                 * Resolves a URL from an URI, if possible.
1109
                 *
1110
                 * @param uri     The URI to represent.
1111
                 * @param handler The stream handler to attach to that URL.
1112
                 * @return An appropriate URL.
1113
                 * @throws MalformedURLException If the supplied URL is malformed.
1114
                 */
1115
                @MaybeNull
1116
                @JavaDispatcher.IsStatic
1117
                @JavaDispatcher.Defaults
1118
                URL of(URI uri, URLStreamHandler handler) throws MalformedURLException;
1119
            }
1120
        }
1121
    }
1122

1123
    /**
1124
     * <p>
1125
     * A {@link net.bytebuddy.dynamic.loading.ByteArrayClassLoader} which applies child-first semantics for the
1126
     * given type definitions.
1127
     * </p>
1128
     * <p>
1129
     * <b>Important</b>: Package definitions remain their parent-first semantics as loaded package definitions do not expose their class loaders.
1130
     * Also, it is not possible to make this class or its subclass parallel-capable as the loading strategy is overridden.
1131
     * </p>
1132
     */
1133
    public static class ChildFirst extends ByteArrayClassLoader {
1134

1135
        /**
1136
         * The suffix of files in the Java class file format.
1137
         */
1138
        private static final String CLASS_FILE_SUFFIX = ".class";
1139

1140
        /*
1141
         * Register class loader as parallel capable if the current VM supports it.
1142
         */
1143
        static {
1144
            doRegisterAsParallelCapable();
1✔
1145
        }
1✔
1146

1147
        /**
1148
         * Registers class loader as parallel capable if possible.
1149
         */
1150
        @SuppressFBWarnings(value = "DP_DO_INSIDE_DO_PRIVILEGED", justification = "Must be invoked from targeting class loader type.")
1151
        private static void doRegisterAsParallelCapable() {
1152
            try {
1153
                Method method = ClassLoader.class.getDeclaredMethod("registerAsParallelCapable");
1✔
1154
                method.setAccessible(true);
1✔
1155
                method.invoke(null);
1✔
UNCOV
1156
            } catch (Throwable ignored) {
×
1157
                /* do nothing */
1158
            }
1✔
1159
        }
1✔
1160

1161
        /**
1162
         * Creates a new child-first byte array class loader.
1163
         *
1164
         * @param parent          The {@link java.lang.ClassLoader} that is the parent of this class loader.
1165
         * @param typeDefinitions A map of fully qualified class names pointing to their binary representations.
1166
         */
1167
        public ChildFirst(@MaybeNull ClassLoader parent, Map<String, byte[]> typeDefinitions) {
UNCOV
1168
            super(parent, typeDefinitions);
×
UNCOV
1169
        }
×
1170

1171
        /**
1172
         * Creates a new child-first byte array class loader.
1173
         *
1174
         * @param parent          The {@link java.lang.ClassLoader} that is the parent of this class loader.
1175
         * @param sealed          {@code true} if this class loader is sealed.
1176
         * @param typeDefinitions A map of fully qualified class names pointing to their binary representations.
1177
         */
1178
        public ChildFirst(@MaybeNull ClassLoader parent, boolean sealed, Map<String, byte[]> typeDefinitions) {
UNCOV
1179
            super(parent, sealed, typeDefinitions);
×
1180
        }
×
1181

1182
        /**
1183
         * Creates a new child-first byte array class loader.
1184
         *
1185
         * @param parent             The {@link java.lang.ClassLoader} that is the parent of this class loader.
1186
         * @param typeDefinitions    A map of fully qualified class names pointing to their binary representations.
1187
         * @param persistenceHandler The persistence handler of this class loader.
1188
         */
1189
        public ChildFirst(@MaybeNull ClassLoader parent, Map<String, byte[]> typeDefinitions, PersistenceHandler persistenceHandler) {
1190
            super(parent, typeDefinitions, persistenceHandler);
1✔
1191
        }
1✔
1192

1193
        /**
1194
         * Creates a new child-first byte array class loader.
1195
         *
1196
         * @param parent             The {@link java.lang.ClassLoader} that is the parent of this class loader.
1197
         * @param sealed             {@code true} if this class loader is sealed.
1198
         * @param typeDefinitions    A map of fully qualified class names pointing to their binary representations.
1199
         * @param persistenceHandler The persistence handler of this class loader.
1200
         */
1201
        public ChildFirst(@MaybeNull ClassLoader parent, boolean sealed, Map<String, byte[]> typeDefinitions, PersistenceHandler persistenceHandler) {
UNCOV
1202
            super(parent, sealed, typeDefinitions, persistenceHandler);
×
1203
        }
×
1204

1205
        /**
1206
         * Creates a new child-first byte array class loader.
1207
         *
1208
         * @param parent                    The {@link java.lang.ClassLoader} that is the parent of this class loader.
1209
         * @param typeDefinitions           A map of fully qualified class names pointing to their binary representations.
1210
         * @param protectionDomain          The protection domain to apply where {@code null} references an implicit protection domain.
1211
         * @param persistenceHandler        The persistence handler of this class loader.
1212
         * @param packageDefinitionStrategy The package definer to be queried for package definitions.
1213
         */
1214
        public ChildFirst(@MaybeNull ClassLoader parent,
1215
                          Map<String, byte[]> typeDefinitions,
1216
                          @MaybeNull ProtectionDomain protectionDomain,
1217
                          PersistenceHandler persistenceHandler,
1218
                          PackageDefinitionStrategy packageDefinitionStrategy) {
1219
            super(parent, typeDefinitions, protectionDomain, persistenceHandler, packageDefinitionStrategy);
1✔
1220
        }
1✔
1221

1222
        /**
1223
         * Creates a new child-first byte array class loader.
1224
         *
1225
         * @param parent                    The {@link java.lang.ClassLoader} that is the parent of this class loader.
1226
         * @param sealed                    {@code true} if this class loader is sealed.
1227
         * @param typeDefinitions           A map of fully qualified class names pointing to their binary representations.
1228
         * @param protectionDomain          The protection domain to apply where {@code null} references an implicit protection domain.
1229
         * @param persistenceHandler        The persistence handler of this class loader.
1230
         * @param packageDefinitionStrategy The package definer to be queried for package definitions.
1231
         */
1232
        public ChildFirst(@MaybeNull ClassLoader parent,
1233
                          boolean sealed,
1234
                          Map<String, byte[]> typeDefinitions,
1235
                          @MaybeNull ProtectionDomain protectionDomain,
1236
                          PersistenceHandler persistenceHandler,
1237
                          PackageDefinitionStrategy packageDefinitionStrategy) {
UNCOV
1238
            super(parent, sealed, typeDefinitions, protectionDomain, persistenceHandler, packageDefinitionStrategy);
×
UNCOV
1239
        }
×
1240

1241
        /**
1242
         * Creates a new child-first byte array class loader.
1243
         *
1244
         * @param parent                    The {@link java.lang.ClassLoader} that is the parent of this class loader.
1245
         * @param typeDefinitions           A map of fully qualified class names pointing to their binary representations.
1246
         * @param protectionDomain          The protection domain to apply where {@code null} references an implicit protection domain.
1247
         * @param persistenceHandler        The persistence handler of this class loader.
1248
         * @param packageDefinitionStrategy The package definer to be queried for package definitions.
1249
         * @param classFilePostProcessor    A post processor for class files to apply p
1250
         */
1251
        public ChildFirst(@MaybeNull ClassLoader parent,
1252
                          Map<String, byte[]> typeDefinitions,
1253
                          @MaybeNull ProtectionDomain protectionDomain,
1254
                          PersistenceHandler persistenceHandler,
1255
                          PackageDefinitionStrategy packageDefinitionStrategy,
1256
                          ClassFilePostProcessor classFilePostProcessor) {
UNCOV
1257
            super(parent, typeDefinitions, protectionDomain, persistenceHandler, packageDefinitionStrategy, classFilePostProcessor);
×
UNCOV
1258
        }
×
1259

1260
        /**
1261
         * Creates a new child-first byte array class loader.
1262
         *
1263
         * @param parent                    The {@link java.lang.ClassLoader} that is the parent of this class loader.
1264
         * @param sealed                    {@code true} if this class loader is sealed.
1265
         * @param typeDefinitions           A map of fully qualified class names pointing to their binary representations.
1266
         * @param protectionDomain          The protection domain to apply where {@code null} references an implicit protection domain.
1267
         * @param persistenceHandler        The persistence handler of this class loader.
1268
         * @param packageDefinitionStrategy The package definer to be queried for package definitions.
1269
         * @param classFilePostProcessor    A post processor for class files to apply p
1270
         */
1271
        public ChildFirst(@MaybeNull ClassLoader parent,
1272
                          boolean sealed,
1273
                          Map<String, byte[]> typeDefinitions,
1274
                          @MaybeNull ProtectionDomain protectionDomain,
1275
                          PersistenceHandler persistenceHandler,
1276
                          PackageDefinitionStrategy packageDefinitionStrategy,
1277
                          ClassFilePostProcessor classFilePostProcessor) {
1278
            super(parent, sealed, typeDefinitions, protectionDomain, persistenceHandler, packageDefinitionStrategy, classFilePostProcessor);
1✔
1279
        }
1✔
1280

1281
        /**
1282
         * Loads a given set of class descriptions and their binary representations using a child-first class loader.
1283
         *
1284
         * @param classLoader The parent class loader.
1285
         * @param types       The unloaded types to be loaded.
1286
         * @return A map of the given type descriptions pointing to their loaded representations.
1287
         */
1288
        public static Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader, Map<TypeDescription, byte[]> types) {
UNCOV
1289
            return load(classLoader,
×
1290
                    types,
1291
                    ClassLoadingStrategy.NO_PROTECTION_DOMAIN,
1292
                    PersistenceHandler.LATENT,
1293
                    PackageDefinitionStrategy.Trivial.INSTANCE,
1294
                    false,
1295
                    true);
1296
        }
1297

1298
        /**
1299
         * Loads a given set of class descriptions and their binary representations using a child-first class loader.
1300
         *
1301
         * @param classLoader               The parent class loader.
1302
         * @param types                     The unloaded types to be loaded.
1303
         * @param protectionDomain          The protection domain to apply where {@code null} references an implicit protection domain.
1304
         * @param persistenceHandler        The persistence handler of the created class loader.
1305
         * @param packageDefinitionStrategy The package definer to be queried for package definitions.
1306
         * @param forbidExisting            {@code true} if the class loading should throw an exception if a class was already loaded by a parent class loader.
1307
         * @param sealed                    {@code true} if the class loader should be sealed.
1308
         * @return A map of the given type descriptions pointing to their loaded representations.
1309
         */
1310
        public static Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader,
1311
                                                          Map<TypeDescription, byte[]> types,
1312
                                                          @MaybeNull ProtectionDomain protectionDomain,
1313
                                                          PersistenceHandler persistenceHandler,
1314
                                                          PackageDefinitionStrategy packageDefinitionStrategy,
1315
                                                          boolean forbidExisting,
1316
                                                          boolean sealed) {
UNCOV
1317
            return load(classLoader,
×
1318
                    types,
1319
                    protectionDomain,
1320
                    persistenceHandler,
1321
                    packageDefinitionStrategy,
1322
                    ClassLoaderDecorator.Factory.NoOp.INSTANCE,
1323
                    forbidExisting,
1324
                    sealed);
1325
        }
1326

1327
        /**
1328
         * Loads a given set of class descriptions and their binary representations using a child-first class loader.
1329
         *
1330
         * @param classLoader                 The parent class loader.
1331
         * @param types                       The unloaded types to be loaded.
1332
         * @param protectionDomain            The protection domain to apply where {@code null} references an implicit protection domain.
1333
         * @param persistenceHandler          The persistence handler of the created class loader.
1334
         * @param packageDefinitionStrategy   The package definer to be queried for package definitions.
1335
         * @param classLoaderDecoratorFactory The class loader decorator factory to use.
1336
         * @param forbidExisting              {@code true} if the class loading should throw an exception if a class was already loaded by a parent class loader.
1337
         * @param sealed                      {@code true} if the class loader should be sealed.
1338
         * @return A map of the given type descriptions pointing to their loaded representations.
1339
         */
1340
        @SuppressFBWarnings(value = "DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED", justification = "Assuring privilege is explicit user responsibility.")
1341
        public static Map<TypeDescription, Class<?>> load(@MaybeNull ClassLoader classLoader,
1342
                                                          Map<TypeDescription, byte[]> types,
1343
                                                          @MaybeNull ProtectionDomain protectionDomain,
1344
                                                          PersistenceHandler persistenceHandler,
1345
                                                          PackageDefinitionStrategy packageDefinitionStrategy,
1346
                                                          ClassLoaderDecorator.Factory classLoaderDecoratorFactory,
1347
                                                          boolean forbidExisting,
1348
                                                          boolean sealed) {
1349
            Map<String, byte[]> typeDefinitions = new HashMap<String, byte[]>();
1✔
1350
            for (Map.Entry<TypeDescription, byte[]> entry : types.entrySet()) {
1✔
1351
                typeDefinitions.put(entry.getKey().getName(), entry.getValue());
1✔
1352
            }
1✔
1353
            classLoader = new ChildFirst(classLoader,
1✔
1354
                    sealed,
1355
                    typeDefinitions,
1356
                    protectionDomain,
1357
                    persistenceHandler,
1358
                    packageDefinitionStrategy,
1359
                    ClassFilePostProcessor.NoOp.INSTANCE);
1360
            ClassLoaderDecorator decorator = classLoaderDecoratorFactory.make(classLoader, typeDefinitions);
1✔
1361
            Map<TypeDescription, Class<?>> result = new LinkedHashMap<TypeDescription, Class<?>>();
1✔
1362
            for (TypeDescription typeDescription : types.keySet()) {
1✔
1363
                if (decorator.isSkipped(typeDescription)) {
1✔
1364
                    continue;
×
1365
                }
1366
                ClassLoader currentClassLoader = decorator.apply(typeDescription);
1✔
1367
                try {
1368
                    Class<?> type = Class.forName(typeDescription.getName(), false, currentClassLoader);
1✔
1369
                    if (!GraalImageCode.getCurrent().isNativeImageExecution() && forbidExisting && type.getClassLoader() != currentClassLoader) {
1✔
UNCOV
1370
                        throw new IllegalStateException("Class already loaded: " + type);
×
1371
                    }
1372
                    result.put(typeDescription, type);
1✔
UNCOV
1373
                } catch (ClassNotFoundException exception) {
×
UNCOV
1374
                    throw new IllegalStateException("Cannot load class " + typeDescription, exception);
×
1375
                }
1✔
1376
            }
1✔
1377
            return result;
1✔
1378
        }
1379

1380
        /**
1381
         * {@inheritDoc}
1382
         */
1383
        protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
1384
            synchronized (SYNCHRONIZATION_STRATEGY.initialize().getClassLoadingLock(this, name)) {
1✔
1385
                Class<?> type = findLoadedClass(name);
1✔
1386
                if (type != null) {
1✔
1387
                    return type;
1✔
1388
                }
1389
                try {
1390
                    type = findClass(name);
1✔
1391
                    if (resolve) {
1✔
UNCOV
1392
                        resolveClass(type);
×
1393
                    }
1394
                    return type;
1✔
1395
                } catch (ClassNotFoundException exception) {
1✔
1396
                    // If an unknown class is loaded, this implementation causes the findClass method of this instance
1397
                    // to be triggered twice. This is however of minor importance because this would result in a
1398
                    // ClassNotFoundException what does not alter the outcome.
1399
                    return super.loadClass(name, resolve);
1✔
1400
                }
1401
            }
1402
        }
1403

1404
        /**
1405
         * {@inheritDoc}
1406
         */
1407
        public URL getResource(String name) {
1408
            URL url = persistenceHandler.url(name, typeDefinitions);
1✔
1409
            // If a class resource is defined by this class loader but it is not defined in a manifest manner,
1410
            // the resource of the parent class loader should be shadowed by 'null'. Note that the delegation
1411
            // model causes a redundant query to the persistent handler but renders a correct result.
1412
            return url != null || isShadowed(name)
1✔
1413
                    ? url
1414
                    : super.getResource(name);
1✔
1415
        }
1416

1417
        /**
1418
         * {@inheritDoc}
1419
         */
1420
        public Enumeration<URL> getResources(String name) throws IOException {
1421
            URL url = persistenceHandler.url(name, typeDefinitions);
1✔
1422
            return url == null
1✔
1423
                    ? super.getResources(name)
1✔
1424
                    : new PrependingEnumeration(url, super.getResources(name));
1✔
1425
        }
1426

1427
        /**
1428
         * Checks if a resource name represents a class file of a class that was loaded by this class loader.
1429
         *
1430
         * @param resource The resource name of the class to be exposed as its class file.
1431
         * @return {@code true} if this class represents a class that is being loaded by this class loader.
1432
         */
1433
        private boolean isShadowed(String resource) {
1434
            if (persistenceHandler.isManifest() || !resource.endsWith(CLASS_FILE_SUFFIX)) {
1✔
1435
                return false;
1✔
1436
            }
1437
            // This synchronization is required to avoid a racing condition to the actual class loading.
1438
            String name = resource.replace('/', '.').substring(0, resource.length() - CLASS_FILE_SUFFIX.length());
1✔
1439
            synchronized (SYNCHRONIZATION_STRATEGY.initialize().getClassLoadingLock(this, name)) {
1✔
1440
                if (typeDefinitions.containsKey(name)) {
1✔
1441
                    return true;
1✔
1442
                }
1443
                Class<?> loadedClass = findLoadedClass(name);
1✔
1444
                return loadedClass != null && loadedClass.getClassLoader() == this;
1✔
1445
            }
1446
        }
1447

1448
        /**
1449
         * An enumeration that prepends an element to another enumeration and skips the last element of the provided enumeration.
1450
         */
1451
        protected static class PrependingEnumeration implements Enumeration<URL> {
1452

1453
            /**
1454
             * The next element to return from this enumeration or {@code null} if such an element does not exist.
1455
             */
1456
            @MaybeNull
1457
            private URL nextElement;
1458

1459
            /**
1460
             * The enumeration from which the next elements should be pulled.
1461
             */
1462
            private final Enumeration<URL> enumeration;
1463

1464
            /**
1465
             * Creates a new prepending enumeration.
1466
             *
1467
             * @param url         The first element of the enumeration.
1468
             * @param enumeration An enumeration that is used for pulling subsequent urls.
1469
             */
1470
            protected PrependingEnumeration(URL url, Enumeration<URL> enumeration) {
1✔
1471
                nextElement = url;
1✔
1472
                this.enumeration = enumeration;
1✔
1473
            }
1✔
1474

1475
            /**
1476
             * {@inheritDoc}
1477
             */
1478
            public boolean hasMoreElements() {
1479
                return nextElement != null && enumeration.hasMoreElements();
1✔
1480
            }
1481

1482
            /**
1483
             * {@inheritDoc}
1484
             */
1485
            public URL nextElement() {
1486
                if (nextElement != null && enumeration.hasMoreElements()) {
1✔
1487
                    try {
1488
                        return nextElement;
1✔
1489
                    } finally {
1490
                        nextElement = enumeration.nextElement();
1✔
1491
                    }
1492
                } else {
1493
                    throw new NoSuchElementException();
1✔
1494
                }
1495
            }
1496
        }
1497
    }
1498

1499
    /**
1500
     * An enumeration without any elements.
1501
     */
1502
    protected enum EmptyEnumeration implements Enumeration<URL> {
1✔
1503

1504
        /**
1505
         * The singleton instance.
1506
         */
1507
        INSTANCE;
1✔
1508

1509
        /**
1510
         * {@inheritDoc}
1511
         */
1512
        public boolean hasMoreElements() {
1513
            return false;
1✔
1514
        }
1515

1516
        /**
1517
         * {@inheritDoc}
1518
         */
1519
        public URL nextElement() {
1520
            throw new NoSuchElementException();
1✔
1521
        }
1522
    }
1523

1524
    /**
1525
     * An enumeration that contains a single element.
1526
     */
1527
    protected static class SingletonEnumeration implements Enumeration<URL> {
1528

1529
        /**
1530
         * The current element or {@code null} if this enumeration does not contain further elements.
1531
         */
1532
        @MaybeNull
1533
        private URL element;
1534

1535
        /**
1536
         * Creates a new singleton enumeration.
1537
         *
1538
         * @param element The only element.
1539
         */
1540
        protected SingletonEnumeration(URL element) {
1✔
1541
            this.element = element;
1✔
1542
        }
1✔
1543

1544
        /**
1545
         * {@inheritDoc}
1546
         */
1547
        public boolean hasMoreElements() {
1548
            return element != null;
1✔
1549
        }
1550

1551
        /**
1552
         * {@inheritDoc}
1553
         */
1554
        public URL nextElement() {
1555
            if (element == null) {
1✔
1556
                throw new NoSuchElementException();
1✔
1557
            } else {
1558
                try {
1559
                    return element;
1✔
1560
                } finally {
1561
                    element = null;
1✔
1562
                }
1563
            }
1564
        }
1565
    }
1566
}
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