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

raphw / byte-buddy / #850

27 Feb 2026 03:40PM UTC coverage: 83.044% (+0.02%) from 83.021%
#850

push

raphw
[release] Release new version

29635 of 35686 relevant lines covered (83.04%)

0.83 hits per line

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

58.99
/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/loading/PackageDefinitionStrategy.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.build.HashCodeAndEqualsPlugin;
20
import net.bytebuddy.utility.nullability.AlwaysNull;
21
import net.bytebuddy.utility.nullability.MaybeNull;
22

23
import java.io.IOException;
24
import java.io.InputStream;
25
import java.net.MalformedURLException;
26
import java.net.URI;
27
import java.net.URL;
28
import java.util.HashMap;
29
import java.util.Map;
30
import java.util.jar.Attributes;
31
import java.util.jar.JarFile;
32
import java.util.jar.Manifest;
33

34
/**
35
 * A package definer is responsible for defining a package's properties when a class of a new package is loaded. Also,
36
 * a package definer can choose not to define a package at all.
37
 */
38
public interface PackageDefinitionStrategy {
39

40
    /**
41
     * Returns a package definition for a given package.
42
     *
43
     * @param classLoader The class loader for which this package is being defined.
44
     * @param packageName The name of the package.
45
     * @param typeName    The name of the type being loaded that triggered the package definition.
46
     * @return A definition of the package.
47
     */
48
    Definition define(ClassLoader classLoader, String packageName, String typeName);
49

50
    /**
51
     * A package definer that does not define any package.
52
     */
53
    enum NoOp implements PackageDefinitionStrategy {
1✔
54

55
        /**
56
         * The singleton instance.
57
         */
58
        INSTANCE;
1✔
59

60
        /**
61
         * {@inheritDoc}
62
         */
63
        public Definition define(ClassLoader classLoader, String packageName, String typeName) {
64
            return Definition.Undefined.INSTANCE;
1✔
65
        }
66
    }
67

68
    /**
69
     * A package definer that only defines packages without any meta data.
70
     */
71
    enum Trivial implements PackageDefinitionStrategy {
1✔
72

73
        /**
74
         * The singleton instance.
75
         */
76
        INSTANCE;
1✔
77

78
        /**
79
         * {@inheritDoc}
80
         */
81
        public Definition define(ClassLoader classLoader, String packageName, String typeName) {
82
            return Definition.Trivial.INSTANCE;
1✔
83
        }
84
    }
85

86
    /**
87
     * A definition of a package.
88
     */
89
    interface Definition {
90

91
        /**
92
         * Indicates if a package should be defined at all.
93
         *
94
         * @return {@code true} if the package is to be defined.
95
         */
96
        boolean isDefined();
97

98
        /**
99
         * Returns the package specification's title or {@code null} if no such title exists. This method must only be called
100
         * for defined package definitions.
101
         *
102
         * @return The package specification's title.
103
         */
104
        @MaybeNull
105
        String getSpecificationTitle();
106

107
        /**
108
         * Returns the package specification's version or {@code null} if no such version exists. This method must only be called
109
         * for defined package definitions.
110
         *
111
         * @return The package specification's version.
112
         */
113
        @MaybeNull
114
        String getSpecificationVersion();
115

116
        /**
117
         * Returns the package specification's vendor or {@code null} if no such vendor exists. This method must only be called
118
         * for defined package definitions.
119
         *
120
         * @return The package specification's vendor.
121
         */
122
        @MaybeNull
123
        String getSpecificationVendor();
124

125
        /**
126
         * Returns the package implementation's title or {@code null} if no such title exists. This method must only be called
127
         * for defined package definitions.
128
         *
129
         * @return The package implementation's title.
130
         */
131
        @MaybeNull
132
        String getImplementationTitle();
133

134
        /**
135
         * Returns the package implementation's version or {@code null} if no such version exists. This method must only be called
136
         * for defined package definitions.
137
         *
138
         * @return The package implementation's version.
139
         */
140
        @MaybeNull
141
        String getImplementationVersion();
142

143
        /**
144
         * Returns the package implementation's vendor or {@code null} if no such vendor exists. This method must only be called
145
         * for defined package definitions.
146
         *
147
         * @return The package implementation's vendor.
148
         */
149
        @MaybeNull
150
        String getImplementationVendor();
151

152
        /**
153
         * The URL representing the seal base. This method must only be called for defined package definitions.
154
         *
155
         * @return The seal base of the package.
156
         */
157
        @MaybeNull
158
        URL getSealBase();
159

160
        /**
161
         * Validates that this package definition is compatible to a previously defined package. This method must only be
162
         * called for defined package definitions.
163
         *
164
         * @param definedPackage The previously defined package.
165
         * @return {@code false} if this package and the defined package's sealing information are not compatible.
166
         */
167
        boolean isCompatibleTo(Package definedPackage);
168

169
        /**
170
         * A canonical implementation of an undefined package.
171
         */
172
        enum Undefined implements Definition {
1✔
173

174
            /**
175
             * The singleton instance.
176
             */
177
            INSTANCE;
1✔
178

179
            /**
180
             * {@inheritDoc}
181
             */
182
            public boolean isDefined() {
183
                return false;
1✔
184
            }
185

186
            /**
187
             * {@inheritDoc}
188
             */
189
            public String getSpecificationTitle() {
190
                throw new IllegalStateException("Cannot read property of undefined package");
1✔
191
            }
192

193
            /**
194
             * {@inheritDoc}
195
             */
196
            public String getSpecificationVersion() {
197
                throw new IllegalStateException("Cannot read property of undefined package");
1✔
198
            }
199

200
            /**
201
             * {@inheritDoc}
202
             */
203
            public String getSpecificationVendor() {
204
                throw new IllegalStateException("Cannot read property of undefined package");
1✔
205
            }
206

207
            /**
208
             * {@inheritDoc}
209
             */
210
            public String getImplementationTitle() {
211
                throw new IllegalStateException("Cannot read property of undefined package");
1✔
212
            }
213

214
            /**
215
             * {@inheritDoc}
216
             */
217
            public String getImplementationVersion() {
218
                throw new IllegalStateException("Cannot read property of undefined package");
1✔
219
            }
220

221
            /**
222
             * {@inheritDoc}
223
             */
224
            public String getImplementationVendor() {
225
                throw new IllegalStateException("Cannot read property of undefined package");
1✔
226
            }
227

228
            /**
229
             * {@inheritDoc}
230
             */
231
            public URL getSealBase() {
232
                throw new IllegalStateException("Cannot read property of undefined package");
1✔
233
            }
234

235
            /**
236
             * {@inheritDoc}
237
             */
238
            public boolean isCompatibleTo(Package definedPackage) {
239
                throw new IllegalStateException("Cannot check compatibility to undefined package");
1✔
240
            }
241
        }
242

243
        /**
244
         * A package definer that defines packages without any meta data.
245
         */
246
        enum Trivial implements Definition {
1✔
247

248
            /**
249
             * The singleton instance.
250
             */
251
            INSTANCE;
1✔
252

253
            /**
254
             * An empty value of a package's property.
255
             */
256
            @AlwaysNull
257
            private static final String NO_VALUE = null;
1✔
258

259
            /**
260
             * Represents an unsealed package.
261
             */
262
            @AlwaysNull
263
            private static final URL NOT_SEALED = null;
1✔
264

265
            /**
266
             * {@inheritDoc}
267
             */
268
            public boolean isDefined() {
269
                return true;
1✔
270
            }
271

272
            /**
273
             * {@inheritDoc}
274
             */
275
            @MaybeNull
276
            public String getSpecificationTitle() {
277
                return NO_VALUE;
1✔
278
            }
279

280
            /**
281
             * {@inheritDoc}
282
             */
283
            @MaybeNull
284
            public String getSpecificationVersion() {
285
                return NO_VALUE;
1✔
286
            }
287

288
            /**
289
             * {@inheritDoc}
290
             */
291
            @MaybeNull
292
            public String getSpecificationVendor() {
293
                return NO_VALUE;
1✔
294
            }
295

296
            /**
297
             * {@inheritDoc}
298
             */
299
            @MaybeNull
300
            public String getImplementationTitle() {
301
                return NO_VALUE;
1✔
302
            }
303

304
            /**
305
             * {@inheritDoc}
306
             */
307
            @MaybeNull
308
            public String getImplementationVersion() {
309
                return NO_VALUE;
1✔
310
            }
311

312
            /**
313
             * {@inheritDoc}
314
             */
315
            public String getImplementationVendor() {
316
                return NO_VALUE;
1✔
317
            }
318

319
            /**
320
             * {@inheritDoc}
321
             */
322
            @MaybeNull
323
            public URL getSealBase() {
324
                return NOT_SEALED;
1✔
325
            }
326

327
            /**
328
             * {@inheritDoc}
329
             */
330
            public boolean isCompatibleTo(Package definedPackage) {
331
                return true;
1✔
332
            }
333
        }
334

335
        /**
336
         * A simple package definition where any property is represented by a value.
337
         */
338
        class Simple implements Definition {
339

340
            /**
341
             * The seal base or {@code null} if the package is not sealed.
342
             */
343
            @MaybeNull
344
            protected final URL sealBase;
345

346
            /**
347
             * The package specification's title or {@code null} if no such title exists.
348
             */
349
            @MaybeNull
350
            private final String specificationTitle;
351

352
            /**
353
             * The package specification's version or {@code null} if no such version exists.
354
             */
355
            @MaybeNull
356
            private final String specificationVersion;
357

358
            /**
359
             * The package specification's vendor or {@code null} if no such vendor exists.
360
             */
361
            @MaybeNull
362
            private final String specificationVendor;
363

364
            /**
365
             * The package implementation's title or {@code null} if no such title exists.
366
             */
367
            @MaybeNull
368
            private final String implementationTitle;
369

370
            /**
371
             * The package implementation's version or {@code null} if no such version exists.
372
             */
373
            @MaybeNull
374
            private final String implementationVersion;
375

376
            /**
377
             * The package implementation's vendor or {@code null} if no such vendor exists.
378
             */
379
            @MaybeNull
380
            private final String implementationVendor;
381

382
            /**
383
             * Creates a new simple package definition.
384
             *
385
             * @param specificationTitle    The package specification's title or {@code null} if no such title exists.
386
             * @param specificationVersion  The package specification's version or {@code null} if no such version exists.
387
             * @param specificationVendor   The package specification's vendor or {@code null} if no such vendor exists.
388
             * @param implementationTitle   The package implementation's title or {@code null} if no such title exists.
389
             * @param implementationVersion The package implementation's version or {@code null} if no such version exists.
390
             * @param implementationVendor  The package implementation's vendor or {@code null} if no such vendor exists.
391
             * @param sealBase              The seal base or {@code null} if the package is not sealed.
392
             */
393
            public Simple(@MaybeNull String specificationTitle,
394
                          @MaybeNull String specificationVersion,
395
                          @MaybeNull String specificationVendor,
396
                          @MaybeNull String implementationTitle,
397
                          @MaybeNull String implementationVersion,
398
                          @MaybeNull String implementationVendor,
399
                          @MaybeNull URL sealBase) {
1✔
400
                this.specificationTitle = specificationTitle;
1✔
401
                this.specificationVersion = specificationVersion;
1✔
402
                this.specificationVendor = specificationVendor;
1✔
403
                this.implementationTitle = implementationTitle;
1✔
404
                this.implementationVersion = implementationVersion;
1✔
405
                this.implementationVendor = implementationVendor;
1✔
406
                this.sealBase = sealBase;
1✔
407
            }
1✔
408

409
            /**
410
             * {@inheritDoc}
411
             */
412
            public boolean isDefined() {
413
                return true;
1✔
414
            }
415

416
            /**
417
             * {@inheritDoc}
418
             */
419
            @MaybeNull
420
            public String getSpecificationTitle() {
421
                return specificationTitle;
1✔
422
            }
423

424
            /**
425
             * {@inheritDoc}
426
             */
427
            @MaybeNull
428
            public String getSpecificationVersion() {
429
                return specificationVersion;
1✔
430
            }
431

432
            /**
433
             * {@inheritDoc}
434
             */
435
            @MaybeNull
436
            public String getSpecificationVendor() {
437
                return specificationVendor;
1✔
438
            }
439

440
            /**
441
             * {@inheritDoc}
442
             */
443
            @MaybeNull
444
            public String getImplementationTitle() {
445
                return implementationTitle;
1✔
446
            }
447

448
            /**
449
             * {@inheritDoc}
450
             */
451
            @MaybeNull
452
            public String getImplementationVersion() {
453
                return implementationVersion;
1✔
454
            }
455

456
            /**
457
             * {@inheritDoc}
458
             */
459
            @MaybeNull
460
            public String getImplementationVendor() {
461
                return implementationVendor;
1✔
462
            }
463

464
            /**
465
             * {@inheritDoc}
466
             */
467
            @MaybeNull
468
            public URL getSealBase() {
469
                return sealBase;
1✔
470
            }
471

472
            /**
473
             * {@inheritDoc}
474
             */
475
            public boolean isCompatibleTo(Package definedPackage) {
476
                if (sealBase == null) {
1✔
477
                    return !definedPackage.isSealed();
1✔
478
                } else {
479
                    return definedPackage.isSealed(sealBase);
1✔
480
                }
481
            }
482

483
            @Override
484
            @SuppressFBWarnings(value = "DMI_BLOCKING_METHODS_ON_URL", justification = "Package sealing relies on URL equality.")
485
            public int hashCode() {
486
                int result = specificationTitle != null ? specificationTitle.hashCode() : 0;
×
487
                result = 31 * result + (specificationVersion != null ? specificationVersion.hashCode() : 0);
×
488
                result = 31 * result + (specificationVendor != null ? specificationVendor.hashCode() : 0);
×
489
                result = 31 * result + (implementationTitle != null ? implementationTitle.hashCode() : 0);
×
490
                result = 31 * result + (implementationVersion != null ? implementationVersion.hashCode() : 0);
×
491
                result = 31 * result + (implementationVendor != null ? implementationVendor.hashCode() : 0);
×
492
                result = 31 * result + (sealBase != null ? sealBase.hashCode() : 0);
×
493
                return result;
×
494
            }
495

496
            @Override
497
            @SuppressFBWarnings(value = "DMI_BLOCKING_METHODS_ON_URL", justification = "Package sealing relies on URL equality.")
498
            public boolean equals(@MaybeNull Object other) {
499
                if (this == other) {
×
500
                    return true;
×
501
                } else if (other == null || getClass() != other.getClass()) {
×
502
                    return false;
×
503
                }
504
                Simple simple = (Simple) other;
×
505
                return !(specificationTitle != null ? !specificationTitle.equals(simple.specificationTitle) : simple.specificationTitle != null)
×
506
                        && !(specificationVersion != null ? !specificationVersion.equals(simple.specificationVersion) : simple.specificationVersion != null)
×
507
                        && !(specificationVendor != null ? !specificationVendor.equals(simple.specificationVendor) : simple.specificationVendor != null)
×
508
                        && !(implementationTitle != null ? !implementationTitle.equals(simple.implementationTitle) : simple.implementationTitle != null)
×
509
                        && !(implementationVersion != null ? !implementationVersion.equals(simple.implementationVersion) : simple.implementationVersion != null)
×
510
                        && !(implementationVendor != null ? !implementationVendor.equals(simple.implementationVendor) : simple.implementationVendor != null)
×
511
                        && !(sealBase != null ? !sealBase.equals(simple.sealBase) : simple.sealBase != null);
×
512
            }
513
        }
514
    }
515

516
    /**
517
     * A package definer that reads a class loader's manifest file.
518
     */
519
    @HashCodeAndEqualsPlugin.Enhance
520
    class ManifestReading implements PackageDefinitionStrategy {
521

522
        /**
523
         * A URL defined a non-sealed package.
524
         */
525
        @AlwaysNull
526
        private static final URL NOT_SEALED = null;
1✔
527

528
        /**
529
         * Contains all attributes that are relevant for defining a package.
530
         */
531
        private static final Attributes.Name[] ATTRIBUTE_NAMES = new Attributes.Name[]{
1✔
532
                Attributes.Name.SPECIFICATION_TITLE,
533
                Attributes.Name.SPECIFICATION_VERSION,
534
                Attributes.Name.SPECIFICATION_VENDOR,
535
                Attributes.Name.IMPLEMENTATION_TITLE,
536
                Attributes.Name.IMPLEMENTATION_VERSION,
537
                Attributes.Name.IMPLEMENTATION_VENDOR,
538
                Attributes.Name.SEALED
539
        };
540

541
        /**
542
         * A locator for a sealed package's URL.
543
         */
544
        private final SealBaseLocator sealBaseLocator;
545

546
        /**
547
         * Creates a manifest reading package definition strategy that attempts to extract sealing information from a defined class's URL.
548
         */
549
        public ManifestReading() {
550
            this(new SealBaseLocator.ForTypeResourceUrl());
×
551
        }
×
552

553
        /**
554
         * Creates a new package definer that reads a class loader's manifest file.
555
         *
556
         * @param sealBaseLocator A locator for a sealed package's URL.
557
         */
558
        public ManifestReading(SealBaseLocator sealBaseLocator) {
1✔
559
            this.sealBaseLocator = sealBaseLocator;
1✔
560
        }
1✔
561

562
        /**
563
         * {@inheritDoc}
564
         */
565
        public Definition define(ClassLoader classLoader, String packageName, String typeName) {
566
            InputStream inputStream = classLoader.getResourceAsStream(JarFile.MANIFEST_NAME);
1✔
567
            if (inputStream != null) {
1✔
568
                try {
569
                    try {
570
                        Manifest manifest = new Manifest(inputStream);
1✔
571
                        Map<Attributes.Name, String> values = new HashMap<Attributes.Name, String>();
1✔
572
                        Attributes mainAttributes = manifest.getMainAttributes();
1✔
573
                        if (mainAttributes != null) {
1✔
574
                            for (Attributes.Name attributeName : ATTRIBUTE_NAMES) {
1✔
575
                                values.put(attributeName, mainAttributes.getValue(attributeName));
1✔
576
                            }
577
                        }
578
                        Attributes attributes = manifest.getAttributes(packageName.replace('.', '/').concat("/"));
1✔
579
                        if (attributes != null) {
1✔
580
                            for (Attributes.Name attributeName : ATTRIBUTE_NAMES) {
1✔
581
                                String value = attributes.getValue(attributeName);
1✔
582
                                if (value != null) {
1✔
583
                                    values.put(attributeName, value);
1✔
584
                                }
585
                            }
586
                        }
587
                        return new Definition.Simple(values.get(Attributes.Name.SPECIFICATION_TITLE),
1✔
588
                                values.get(Attributes.Name.SPECIFICATION_VERSION),
1✔
589
                                values.get(Attributes.Name.SPECIFICATION_VENDOR),
1✔
590
                                values.get(Attributes.Name.IMPLEMENTATION_TITLE),
1✔
591
                                values.get(Attributes.Name.IMPLEMENTATION_VERSION),
1✔
592
                                values.get(Attributes.Name.IMPLEMENTATION_VENDOR),
1✔
593
                                Boolean.parseBoolean(values.get(Attributes.Name.SEALED))
1✔
594
                                        ? sealBaseLocator.findSealBase(classLoader, typeName)
1✔
595
                                        : NOT_SEALED);
596
                    } finally {
597
                        inputStream.close();
1✔
598
                    }
599
                } catch (IOException exception) {
×
600
                    throw new IllegalStateException("Error while reading manifest file", exception);
×
601
                }
602
            } else {
603
                return Definition.Trivial.INSTANCE;
1✔
604
            }
605
        }
606

607
        /**
608
         * A locator for a seal base URL.
609
         */
610
        public interface SealBaseLocator {
611

612
            /**
613
             * Locates the URL that should be used for sealing a package.
614
             *
615
             * @param classLoader The class loader loading the package.
616
             * @param typeName    The name of the type being loaded that triggered the package definition.
617
             * @return The URL that is used for sealing a package or {@code null} if the package should not be sealed.
618
             */
619
            @MaybeNull
620
            URL findSealBase(ClassLoader classLoader, String typeName);
621

622
            /**
623
             * A seal base locator that never seals a package.
624
             */
625
            enum NonSealing implements SealBaseLocator {
1✔
626

627
                /**
628
                 * The singleton instance.
629
                 */
630
                INSTANCE;
1✔
631

632
                /**
633
                 * {@inheritDoc}
634
                 */
635
                @MaybeNull
636
                public URL findSealBase(ClassLoader classLoader, String typeName) {
637
                    return NOT_SEALED;
1✔
638
                }
639
            }
640

641
            /**
642
             * A seal base locator that seals all packages with a fixed URL.
643
             */
644
            @HashCodeAndEqualsPlugin.Enhance
645
            class ForFixedValue implements SealBaseLocator {
646

647
                /**
648
                 * The seal base URL.
649
                 */
650
                @MaybeNull
651
                @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
652
                private final URL sealBase;
653

654
                /**
655
                 * Creates a new seal base locator for a fixed URL.
656
                 *
657
                 * @param sealBase The seal base URL.
658
                 */
659
                public ForFixedValue(@MaybeNull URL sealBase) {
×
660
                    this.sealBase = sealBase;
×
661
                }
×
662

663
                /**
664
                 * {@inheritDoc}
665
                 */
666
                @MaybeNull
667
                public URL findSealBase(ClassLoader classLoader, String typeName) {
668
                    return sealBase;
×
669
                }
670

671
                @Override
672
                @SuppressFBWarnings(value = "DMI_BLOCKING_METHODS_ON_URL", justification = "Package sealing relies on URL equality.")
673
                public int hashCode() {
674
                    return sealBase == null
×
675
                            ? 17
676
                            : sealBase.hashCode();
×
677
                }
678

679
                @Override
680
                @SuppressFBWarnings(value = "DMI_BLOCKING_METHODS_ON_URL", justification = "Package sealing relies on URL equality.")
681
                public boolean equals(@MaybeNull Object other) {
682
                    if (this == other) {
×
683
                        return true;
×
684
                    } else if (other == null || getClass() != other.getClass()) {
×
685
                        return false;
×
686
                    }
687
                    ForFixedValue forFixedValue = (ForFixedValue) other;
×
688
                    return sealBase == null
×
689
                            ? forFixedValue.sealBase == null
690
                            : sealBase.equals(forFixedValue.sealBase);
×
691
                }
692
            }
693

694
            /**
695
             * A seal base locator that imitates the behavior of a {@link java.net.URLClassLoader}, i.e. tries
696
             * to deduct the base from a class's resource URL.
697
             */
698
            @HashCodeAndEqualsPlugin.Enhance
699
            class ForTypeResourceUrl implements SealBaseLocator {
700

701
                /**
702
                 * An index to indicate to a {@link String} manipulation that the initial slash should be excluded.
703
                 */
704
                private static final int EXCLUDE_INITIAL_SLASH = 1;
705

706
                /**
707
                 * The file extension for a class file.
708
                 */
709
                private static final String CLASS_FILE_EXTENSION = ".class";
710

711
                /**
712
                 * The protocol name of a jar file.
713
                 */
714
                private static final String JAR_FILE = "jar";
715

716
                /**
717
                 * The protocol name of a file system link.
718
                 */
719
                private static final String FILE_SYSTEM = "file";
720

721
                /**
722
                 * The protocol name of a Java 9 runtime image.
723
                 */
724
                private static final String RUNTIME_IMAGE = "jrt";
725

726
                /**
727
                 * The seal base locator to fallback to when a resource is not found or an unexpected URL protocol is discovered.
728
                 */
729
                private final SealBaseLocator fallback;
730

731
                /**
732
                 * Creates a new seal base locator that attempts deduction from a type's URL while using a
733
                 * {@link net.bytebuddy.dynamic.loading.PackageDefinitionStrategy.ManifestReading.SealBaseLocator.NonSealing} seal base locator
734
                 * as a fallback.
735
                 */
736
                public ForTypeResourceUrl() {
737
                    this(NonSealing.INSTANCE);
×
738
                }
×
739

740
                /**
741
                 * Creates a new seal base locator that attempts deduction from a type's URL.
742
                 *
743
                 * @param fallback The seal base locator to fallback to when a resource is not found or an unexpected URL protocol is discovered.
744
                 */
745
                public ForTypeResourceUrl(SealBaseLocator fallback) {
×
746
                    this.fallback = fallback;
×
747
                }
×
748

749
                /**
750
                 * {@inheritDoc}
751
                 */
752
                @MaybeNull
753
                public URL findSealBase(ClassLoader classLoader, String typeName) {
754
                    URL url = classLoader.getResource(typeName.replace('.', '/') + CLASS_FILE_EXTENSION);
×
755
                    if (url != null) {
×
756
                        try {
757
                            if (url.getProtocol().equals(JAR_FILE)) {
×
758
                                return URI.create(url.getPath().substring(0, url.getPath().indexOf('!'))).toURL();
×
759
                            } else if (url.getProtocol().equals(FILE_SYSTEM)) {
×
760
                                return url;
×
761
                            } else if (url.getProtocol().equals(RUNTIME_IMAGE)) {
×
762
                                String path = url.getPath();
×
763
                                int modulePathIndex = path.indexOf('/', EXCLUDE_INITIAL_SLASH);
×
764
                                return modulePathIndex == -1
×
765
                                        ? url
766
                                        : URI.create(RUNTIME_IMAGE + ":" + path.substring(0, modulePathIndex)).toURL();
×
767
                            }
768
                        } catch (MalformedURLException exception) {
×
769
                            throw new IllegalStateException("Unexpected URL: " + url, exception);
×
770
                        }
×
771
                    }
772
                    return fallback.findSealBase(classLoader, typeName);
×
773
                }
774
            }
775
        }
776
    }
777
}
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