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

raphw / byte-buddy / #776

15 Jun 2025 10:22PM UTC coverage: 85.136% (-0.04%) from 85.177%
#776

push

raphw
Add additional test and assure lazy resolution of some modifier properties.

4 of 4 new or added lines in 1 file covered. (100.0%)

597 existing lines in 5 files now uncovered.

29538 of 34695 relevant lines covered (85.14%)

0.85 hits per line

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

50.91
/byte-buddy-dep/src/main/java/net/bytebuddy/utility/AsmClassReader.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.utility;
17

18
import net.bytebuddy.ClassFileVersion;
19
import net.bytebuddy.build.AccessControllerPlugin;
20
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
21
import net.bytebuddy.utility.dispatcher.JavaDispatcher;
22
import net.bytebuddy.utility.nullability.MaybeNull;
23
import net.bytebuddy.utility.privilege.GetSystemPropertyAction;
24
import org.objectweb.asm.Attribute;
25
import org.objectweb.asm.ClassReader;
26
import org.objectweb.asm.ClassVisitor;
27

28
import java.security.PrivilegedAction;
29
import java.util.Arrays;
30
import java.util.Collections;
31
import java.util.List;
32

33
/**
34
 * A facade for creating a class reader that accepts {@link ClassVisitor} instances and reader flags.
35
 */
36
public interface AsmClassReader {
37

38
    /**
39
     * Indicates that no custom attributes should be mapped.
40
     */
41
    Attribute[] NO_ATTRIBUTES = new Attribute[0];
1✔
42

43
    /**
44
     * Unwraps a class reader to the underlying reader mechanism.
45
     *
46
     * @param type The type of the reader that should be unwrapped.
47
     * @param <T>  The type to unwrap.
48
     * @return The unwrapped instance or {@code null} if the underlying instance does not represent this type.
49
     */
50
    @MaybeNull
51
    <T> T unwrap(Class<T> type);
52

53
    /**
54
     * Returns the modifiers of the represented class. The property is read, if possible, without parsing the entire
55
     * class file.
56
     *
57
     * @return The modifiers of the represented class.
58
     */
59
    int getModifiers();
60

61
    /**
62
     * Returns the internal name of the represented class. The property is read, if possible, without parsing
63
     * the entire class file.
64
     *
65
     * @return The internal name of the represented class.
66
     */
67
    String getInternalName();
68

69
    /**
70
     * Returns the internal name of the represented class's super class, or {@code null} if no such class exists.
71
     * The property is read, if possible, without parsing the entire class file.
72
     *
73
     * @return The internal name of the represented class's super class, or {@code null} if no such class exists.
74
     */
75
    @MaybeNull
76
    String getSuperClassInternalName();
77

78
    /**
79
     * Returns the internal names of the represented class's interfaces. The property is read, if possible,
80
     * without parsing the entire class file.
81
     *
82
     * @return Returns the internal names of the represented class's interfaces.
83
     */
84
    List<String> getInterfaceInternalNames();
85

86
    /**
87
     * Accepts a class visitor to read a class.
88
     *
89
     * @param classVisitor The class visitor who should be used as a callback for a class file.
90
     * @param flags        The flags to consider while reading a class.
91
     */
92
    void accept(ClassVisitor classVisitor, int flags);
93

94
    /**
95
     * A factory to create a {@link AsmClassReader}.
96
     */
97
    interface Factory {
98

99
        /**
100
         * Creates a class reader for a given class file.
101
         *
102
         * @param binaryRepresentation The class file's binary representation.
103
         * @return A class reader representation for the supplied class file.
104
         */
105
        AsmClassReader make(byte[] binaryRepresentation);
106

107
        /**
108
         * Creates a class reader for a given class file.
109
         *
110
         * @param binaryRepresentation The class file's binary representation.
111
         * @param experimental         {@code true} if unknown Java class files versions should also be considered.
112
         * @return A class reader representation for the supplied class file.
113
         */
114
        AsmClassReader make(byte[] binaryRepresentation, boolean experimental);
115

116
        /**
117
         * Default implementations for factories of {@link AsmClassReader}s.
118
         */
119
        enum Default implements Factory {
1✔
120

121
            /**
122
             * Uses a processor as it is configured by {@link OpenedClassReader#PROCESSOR_PROPERTY},
123
             * or {@link AsmClassWriter.Factory.Default#ASM_FIRST} if no implicit processor is defined.
124
             */
125
            IMPLICIT {
1✔
126
                /**
127
                 * {@inheritDoc}
128
                 */
129
                public AsmClassReader make(byte[] binaryRepresentation, boolean experimental) {
130
                    return (FACTORY == IMPLICIT ? ASM_FIRST : FACTORY).make(binaryRepresentation, experimental);
1✔
131
                }
132
            },
133

134
            /**
135
             * A factory for a class reader that uses ASM's internal implementation whenever possible.
136
             */
137
            ASM_FIRST {
1✔
138
                /**
139
                 * {@inheritDoc}
140
                 */
141
                public AsmClassReader make(byte[] binaryRepresentation, boolean experimental) {
142
                    return ClassFileVersion.ofThisVm().isGreaterThan(ClassFileVersion.latest())
1✔
143
                            ? CLASS_FILE_API_ONLY.make(binaryRepresentation, experimental)
1✔
144
                            : ASM_ONLY.make(binaryRepresentation, experimental);
1✔
145
                }
146
            },
147

148
            /**
149
             * A factory for a class reader that uses the class file API whenever possible.
150
             */
151
            CLASS_FILE_API_FIRST {
1✔
152
                /**
153
                 * {@inheritDoc}
154
                 */
155
                public AsmClassReader make(byte[] binaryRepresentation, boolean experimental) {
UNCOV
156
                    return ClassFileVersion.ofThisVm().isAtLeast(ClassFileVersion.JAVA_V24)
×
UNCOV
157
                            ? CLASS_FILE_API_ONLY.make(binaryRepresentation, experimental)
×
UNCOV
158
                            : ASM_ONLY.make(binaryRepresentation, experimental);
×
159
                }
160
            },
161

162
            /**
163
             * A factory for a class reader that always uses ASM's internal implementation.
164
             */
165
            ASM_ONLY {
1✔
166
                /**
167
                 * {@inheritDoc}
168
                 */
169
                public AsmClassReader make(byte[] binaryRepresentation, boolean experimental) {
170
                    return new ForAsm(OpenedClassReader.of(binaryRepresentation, experimental));
1✔
171
                }
172
            },
173

174
            /**
175
             * A factory for a class reader that always uses the class file API.
176
             */
177
            CLASS_FILE_API_ONLY {
1✔
178
                /**
179
                 * {@inheritDoc}
180
                 */
181
                public AsmClassReader make(byte[] binaryRepresentation, boolean experimental) {
UNCOV
182
                    return new AsmClassReader.ForClassFileApi(ForClassFileApi.DISPATCHER.make(
×
183
                            binaryRepresentation,
184
                            NO_ATTRIBUTES));
185
                }
186
            };
187

188
            /**
189
             * The implicit factory to use for writing class files.
190
             */
191
            private static final Factory FACTORY;
192

193
            /*
194
             * Resolves the implicit reader factory, if any.
195
             */
196
            static {
197
                String processor;
198
                try {
199
                    processor = doPrivileged(new GetSystemPropertyAction(OpenedClassReader.PROCESSOR_PROPERTY));
1✔
UNCOV
200
                } catch (Throwable ignored) {
×
UNCOV
201
                    processor = null;
×
202
                }
1✔
203
                FACTORY = processor == null ? Default.ASM_FIRST : Default.valueOf(processor);
1✔
204
            }
1✔
205

206
            /**
207
             * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
208
             *
209
             * @param action The action to execute from a privileged context.
210
             * @param <T>    The type of the action's resolved value.
211
             * @return The action's resolved value.
212
             */
213
            @MaybeNull
214
            @AccessControllerPlugin.Enhance
215
            private static <T> T doPrivileged(PrivilegedAction<T> action) {
UNCOV
216
                return action.run();
×
217
            }
218

219
            /**
220
             * {@inheritDoc}
221
             */
222
            public AsmClassReader make(byte[] binaryRepresentation) {
223
                return make(binaryRepresentation, OpenedClassReader.EXPERIMENTAL);
1✔
224
            }
225
        }
226
    }
227

228
    /**
229
     * A class reader for ASM's own {@link ClassReader}.
230
     */
231
    class ForAsm implements AsmClassReader {
232

233
        /**
234
         * The class reader that represents the class file to be read.
235
         */
236
        private final ClassReader classReader;
237

238
        /**
239
         * Creates a new ASM class reader that uses ASM's internal implementation.
240
         *
241
         * @param classReader The class reader that represents the class file to be read.
242
         */
243
        public ForAsm(ClassReader classReader) {
1✔
244
            this.classReader = classReader;
1✔
245
        }
1✔
246

247
        /**
248
         * {@inheritDoc}
249
         */
250
        @MaybeNull
251
        public <T> T unwrap(Class<T> type) {
252
            return type.isInstance(classReader)
1✔
253
                    ? type.cast(classReader)
1✔
254
                    : null;
255
        }
256

257
        /**
258
         * {@inheritDoc}
259
         */
260
        public int getModifiers() {
261
            return classReader.getAccess();
1✔
262
        }
263

264
        /**
265
         * {@inheritDoc}
266
         */
267
        public String getInternalName() {
268
            return classReader.getClassName();
×
269
        }
270

271
        /**
272
         * {@inheritDoc}
273
         */
274
        public String getSuperClassInternalName() {
275
            return classReader.getSuperName();
1✔
276
        }
277

278
        /**
279
         * {@inheritDoc}
280
         */
281
        public List<String> getInterfaceInternalNames() {
282
            String[] value = classReader.getInterfaces();
1✔
283
            return value == null ? Collections.<String>emptyList() : Arrays.asList(value);
1✔
284
        }
285

286
        /**
287
         * {@inheritDoc}
288
         */
289
        public void accept(ClassVisitor classVisitor, int flags) {
290
            classReader.accept(classVisitor, NO_ATTRIBUTES, flags);
1✔
291
        }
1✔
292
    }
293

294
    /**
295
     * A class reader that is based upon the Class File API.
296
     */
297
    @HashCodeAndEqualsPlugin.Enhance
298
    class ForClassFileApi implements AsmClassReader {
299

300
        /**
301
         * A dispatcher to interact with {@code codes.rafael.asmjdkbridge.JdkClassReader}.
302
         */
UNCOV
303
        protected static final JdkClassReader DISPATCHER = doPrivileged(JavaDispatcher.of(
×
304
                JdkClassReader.class,
UNCOV
305
                ForClassFileApi.class.getClassLoader()));
×
306

307
        /**
308
         * The class reader that represents the class file to be read.
309
         */
310
        private final Object classReader;
311

312
        /**
313
         * Creates a new class reader that is based upon the Class File API.
314
         *
315
         * @param classReader The class reader that represents the class file to be read.
316
         */
UNCOV
317
        public ForClassFileApi(Object classReader) {
×
UNCOV
318
            if (!DISPATCHER.isInstance(classReader)) {
×
UNCOV
319
                throw new IllegalArgumentException();
×
320
            }
UNCOV
321
            this.classReader = classReader;
×
UNCOV
322
        }
×
323

324
        /**
325
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
326
         *
327
         * @param action The action to execute from a privileged context.
328
         * @param <T>    The type of the action's resolved value.
329
         * @return The action's resolved value.
330
         */
331
        @AccessControllerPlugin.Enhance
332
        private static <T> T doPrivileged(PrivilegedAction<T> action) {
UNCOV
333
            return action.run();
×
334
        }
335

336
        /**
337
         * {@inheritDoc}
338
         */
339
        @MaybeNull
340
        public <T> T unwrap(Class<T> type) {
UNCOV
341
            return type.isInstance(classReader)
×
UNCOV
342
                    ? type.cast(classReader)
×
343
                    : null;
344
        }
345

346
        /**
347
         * {@inheritDoc}
348
         */
349
        public int getModifiers() {
UNCOV
350
            return DISPATCHER.getAccess(classReader);
×
351
        }
352

353
        /**
354
         * {@inheritDoc}
355
         */
356
        public String getInternalName() {
UNCOV
357
            return DISPATCHER.getClassName(classReader);
×
358
        }
359

360
        /**
361
         * {@inheritDoc}
362
         */
363
        @MaybeNull
364
        public String getSuperClassInternalName() {
UNCOV
365
            return DISPATCHER.getSuperClass(classReader);
×
366
        }
367

368
        /**
369
         * {@inheritDoc}
370
         */
371
        public List<String> getInterfaceInternalNames() {
UNCOV
372
            String[] value = DISPATCHER.getInterfaces(classReader);
×
UNCOV
373
            return value == null ? Collections.<String>emptyList() : Arrays.asList(value);
×
374
        }
375

376
        /**
377
         * {@inheritDoc}
378
         */
379
        @MaybeNull
380
        public String getSuperClassName() {
UNCOV
381
            return DISPATCHER.getSuperClass(classReader);
×
382
        }
383

384
        /**
385
         * {@inheritDoc}
386
         */
387
        @MaybeNull
388
        public String[] getInterfaceTypeName() {
UNCOV
389
            return DISPATCHER.getInterfaces(classReader);
×
390
        }
391

392
        /**
393
         * {@inheritDoc}
394
         */
395
        public void accept(ClassVisitor classVisitor, int flags) {
UNCOV
396
            DISPATCHER.accept(classReader, classVisitor, flags);
×
UNCOV
397
        }
×
398

399
        /**
400
         * A dispatcher to interact with {@code codes.rafael.asmjdkbridge.JdkClassReader}.
401
         */
402
        @JavaDispatcher.Proxied("codes.rafael.asmjdkbridge.JdkClassReader")
403
        protected interface JdkClassReader {
404

405
            /**
406
             * Checks if the supplied object is an instance of {@code codes.rafael.asmjdkbridge.JdkClassReader}.
407
             *
408
             * @param value The instance to evaluate.
409
             * @return {@code true} if the supplied object is an instance of {@code codes.rafael.asmjdkbridge.JdkClassReader}.
410
             */
411
            @JavaDispatcher.Instance
412
            boolean isInstance(Object value);
413

414
            /**
415
             * Creates an instance of {@code codes.rafael.asmjdkbridge.JdkClassReader}.
416
             *
417
             * @param binaryRepresentation The binary representation of a class file to represent through the reader.
418
             * @param attribute            An array of attribute prototypes.
419
             * @return A new instance of {@code codes.rafael.asmjdkbridge.JdkClassReader}.
420
             */
421
            @JavaDispatcher.IsConstructor
422
            Object make(byte[] binaryRepresentation, Attribute[] attribute);
423

424
            /**
425
             * Returns the access flags of the underlying {@code codes.rafael.asmjdkbridge.JdkClassReader}.
426
             *
427
             * @param classReader The class reader that is being queried.
428
             * @return The access flags of the underlying {@code codes.rafael.asmjdkbridge.JdkClassReader}.
429
             */
430
            int getAccess(Object classReader);
431

432
            /**
433
             * Returns the internal name of the represented type.
434
             *
435
             * @param classReader The class reader that is being queried.
436
             * @return The internal name of the represented type.
437
             */
438
            String getClassName(Object classReader);
439

440
            /**
441
             * Returns the internal name of the represented type's super class or {@code null} if there is none.
442
             *
443
             * @param classReader The class reader that is being queried.
444
             * @return The internal name of the represented type's super class or {@code null} if there is none.
445
             */
446
            @MaybeNull
447
            String getSuperClass(Object classReader);
448

449
            /**
450
             * Returns an array of internal names of the represented type's interface types, or {@code null} if none.
451
             *
452
             * @param classReader The class reader that is being queried.
453
             * @return An array of internal names of the represented type's interface types, or {@code null} if none.
454
             */
455
            @MaybeNull
456
            String[] getInterfaces(Object classReader);
457

458
            /**
459
             * Accepts a class reader to visit the represented class file.
460
             *
461
             * @param classReader  The class reader that is being visited.
462
             * @param classVisitor The class visitor to visit the class.
463
             * @param flags        The flags to consider during reading.
464
             */
465
            void accept(Object classReader, ClassVisitor classVisitor, int flags);
466
        }
467
    }
468
}
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