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

raphw / byte-buddy / #801

27 Oct 2025 09:37AM UTC coverage: 84.715% (-0.4%) from 85.118%
#801

push

raphw
Fix imports.

29586 of 34924 relevant lines covered (84.72%)

0.85 hits per line

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

98.59
/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/attribute/AnnotationAppender.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.implementation.attribute;
17

18
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
20
import net.bytebuddy.description.annotation.AnnotationDescription;
21
import net.bytebuddy.description.enumeration.EnumerationDescription;
22
import net.bytebuddy.description.method.MethodDescription;
23
import net.bytebuddy.description.type.TypeDescription;
24
import net.bytebuddy.description.type.TypeList;
25
import net.bytebuddy.utility.nullability.AlwaysNull;
26
import net.bytebuddy.utility.nullability.MaybeNull;
27
import org.objectweb.asm.AnnotationVisitor;
28
import org.objectweb.asm.ClassVisitor;
29
import org.objectweb.asm.FieldVisitor;
30
import org.objectweb.asm.MethodVisitor;
31
import org.objectweb.asm.RecordComponentVisitor;
32
import org.objectweb.asm.Type;
33
import org.objectweb.asm.TypePath;
34
import org.objectweb.asm.TypeReference;
35

36
import java.lang.reflect.Array;
37
import java.util.List;
38

39
/**
40
 * Annotation appenders are capable of writing annotations to a specified target.
41
 */
42
public interface AnnotationAppender {
43

44
    /**
45
     * A constant for informing ASM over ignoring a given name.
46
     */
47
    @AlwaysNull
48
    String NO_NAME = null;
1✔
49

50
    /**
51
     * Writes the given annotation to the target that this appender represents.
52
     *
53
     * @param annotationDescription The annotation to be written.
54
     * @param annotationValueFilter The annotation value filter to use.
55
     * @return Usually {@code this} or any other annotation appender capable of writing another annotation to the specified target.
56
     */
57
    AnnotationAppender append(AnnotationDescription annotationDescription, AnnotationValueFilter annotationValueFilter);
58

59
    /**
60
     * Writes the given type annotation to the target that this appender represents.
61
     *
62
     * @param annotationDescription The annotation to be written.
63
     * @param annotationValueFilter The annotation value filter to use.
64
     * @param typeReference         The type variable's type reference.
65
     * @param typePath              The type variable's type path.
66
     * @return Usually {@code this} or any other annotation appender capable of writing another annotation to the specified target.
67
     */
68
    AnnotationAppender append(AnnotationDescription annotationDescription, AnnotationValueFilter annotationValueFilter, int typeReference, String typePath);
69

70
    /**
71
     * Represents a target for an annotation writing process.
72
     */
73
    interface Target {
74

75
        /**
76
         * Creates an annotation visitor for writing the specified annotation.
77
         *
78
         * @param annotationTypeDescriptor The type descriptor for the annotation to be written.
79
         * @param visible                  {@code true} if the annotation is to be visible at runtime.
80
         * @return An annotation visitor for consuming the specified annotation.
81
         */
82
        @MaybeNull
83
        AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible);
84

85
        /**
86
         * Creates an annotation visitor for writing the specified type annotation.
87
         *
88
         * @param annotationTypeDescriptor The type descriptor for the annotation to be written.
89
         * @param visible                  {@code true} if the annotation is to be visible at runtime.
90
         * @param typeReference            The type annotation's type reference.
91
         * @param typePath                 The type annotation's type path.
92
         * @return An annotation visitor for consuming the specified annotation.
93
         */
94
        @MaybeNull
95
        AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible, int typeReference, String typePath);
96

97
        /**
98
         * Target for an annotation that is written to a Java type.
99
         */
100
        @HashCodeAndEqualsPlugin.Enhance
101
        class OnType implements Target {
102

103
            /**
104
             * The class visitor to write the annotation to.
105
             */
106
            private final ClassVisitor classVisitor;
107

108
            /**
109
             * Creates a new wrapper for a Java type.
110
             *
111
             * @param classVisitor The ASM class visitor to which the annotations are appended to.
112
             */
113
            public OnType(ClassVisitor classVisitor) {
1✔
114
                this.classVisitor = classVisitor;
1✔
115
            }
1✔
116

117
            /**
118
             * {@inheritDoc}
119
             */
120
            @MaybeNull
121
            public AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible) {
122
                return classVisitor.visitAnnotation(annotationTypeDescriptor, visible);
1✔
123
            }
124

125
            /**
126
             * {@inheritDoc}
127
             */
128
            @MaybeNull
129
            public AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible, int typeReference, String typePath) {
130
                return classVisitor.visitTypeAnnotation(typeReference, TypePath.fromString(typePath), annotationTypeDescriptor, visible);
1✔
131
            }
132
        }
133

134
        /**
135
         * Target for an annotation that is written to a Java field.
136
         */
137
        @HashCodeAndEqualsPlugin.Enhance
138
        class OnField implements Target {
139

140
            /**
141
             * The field visitor to write the annotation to.
142
             */
143
            private final FieldVisitor fieldVisitor;
144

145
            /**
146
             * Creates a new wrapper for a Java field.
147
             *
148
             * @param fieldVisitor The ASM field visitor to which the annotations are appended to.
149
             */
150
            public OnField(FieldVisitor fieldVisitor) {
1✔
151
                this.fieldVisitor = fieldVisitor;
1✔
152
            }
1✔
153

154
            /**
155
             * {@inheritDoc}
156
             */
157
            @MaybeNull
158
            public AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible) {
159
                return fieldVisitor.visitAnnotation(annotationTypeDescriptor, visible);
1✔
160
            }
161

162
            /**
163
             * {@inheritDoc}
164
             */
165
            @MaybeNull
166
            public AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible, int typeReference, String typePath) {
167
                return fieldVisitor.visitTypeAnnotation(typeReference, TypePath.fromString(typePath), annotationTypeDescriptor, visible);
1✔
168
            }
169
        }
170

171
        /**
172
         * Target for an annotation that is written to a Java method or constructor.
173
         */
174
        @HashCodeAndEqualsPlugin.Enhance
175
        class OnMethod implements Target {
176

177
            /**
178
             * The method visitor to write the annotation to.
179
             */
180
            private final MethodVisitor methodVisitor;
181

182
            /**
183
             * Creates a new wrapper for a Java method or constructor.
184
             *
185
             * @param methodVisitor The ASM method visitor to which the annotations are appended to.
186
             */
187
            public OnMethod(MethodVisitor methodVisitor) {
1✔
188
                this.methodVisitor = methodVisitor;
1✔
189
            }
1✔
190

191
            /**
192
             * {@inheritDoc}
193
             */
194
            @MaybeNull
195
            public AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible) {
196
                return methodVisitor.visitAnnotation(annotationTypeDescriptor, visible);
1✔
197
            }
198

199
            /**
200
             * {@inheritDoc}
201
             */
202
            @MaybeNull
203
            public AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible, int typeReference, String typePath) {
204
                return methodVisitor.visitTypeAnnotation(typeReference, TypePath.fromString(typePath), annotationTypeDescriptor, visible);
1✔
205
            }
206
        }
207

208
        /**
209
         * Target for an annotation that is written to a Java method or constructor parameter.
210
         */
211
        @HashCodeAndEqualsPlugin.Enhance
212
        class OnMethodParameter implements Target {
213

214
            /**
215
             * The method visitor to write the annotation to.
216
             */
217
            private final MethodVisitor methodVisitor;
218

219
            /**
220
             * The method parameter index to write the annotation to.
221
             */
222
            private final int parameterIndex;
223

224
            /**
225
             * Creates a new wrapper for a Java method or constructor.
226
             *
227
             * @param methodVisitor  The ASM method visitor to which the annotations are appended to.
228
             * @param parameterIndex The index of the method parameter.
229
             */
230
            public OnMethodParameter(MethodVisitor methodVisitor, int parameterIndex) {
1✔
231
                this.methodVisitor = methodVisitor;
1✔
232
                this.parameterIndex = parameterIndex;
1✔
233
            }
1✔
234

235
            /**
236
             * {@inheritDoc}
237
             */
238
            @MaybeNull
239
            public AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible) {
240
                return methodVisitor.visitParameterAnnotation(parameterIndex, annotationTypeDescriptor, visible);
1✔
241
            }
242

243
            /**
244
             * {@inheritDoc}
245
             */
246
            @MaybeNull
247
            public AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible, int typeReference, String typePath) {
248
                return methodVisitor.visitTypeAnnotation(typeReference, TypePath.fromString(typePath), annotationTypeDescriptor, visible);
1✔
249
            }
250
        }
251

252
        /**
253
         * Target for an annotation that is written to a Java record component.
254
         */
255
        @HashCodeAndEqualsPlugin.Enhance
256
        class OnRecordComponent implements Target {
257

258
            /**
259
             * The record component visitor to write the annotation to.
260
             */
261
            private final RecordComponentVisitor recordComponentVisitor;
262

263
            /**
264
             * Creates a new wrapper for a Java record component.
265
             *
266
             * @param recordComponentVisitor The record component visitor to write the annotation to.
267
             */
268
            public OnRecordComponent(RecordComponentVisitor recordComponentVisitor) {
1✔
269
                this.recordComponentVisitor = recordComponentVisitor;
1✔
270
            }
1✔
271

272
            /**
273
             * {@inheritDoc}
274
             */
275
            @MaybeNull
276
            public AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible) {
277
                return recordComponentVisitor.visitAnnotation(annotationTypeDescriptor, visible);
1✔
278
            }
279

280
            /**
281
             * {@inheritDoc}
282
             */
283
            @MaybeNull
284
            public AnnotationVisitor visit(String annotationTypeDescriptor, boolean visible, int typeReference, String typePath) {
285
                return recordComponentVisitor.visitTypeAnnotation(typeReference, TypePath.fromString(typePath), annotationTypeDescriptor, visible);
1✔
286
            }
287
        }
288
    }
289

290
    /**
291
     * A default implementation for an annotation appender that writes annotations to a given byte consumer
292
     * represented by an ASM {@link org.objectweb.asm.AnnotationVisitor}.
293
     */
294
    @HashCodeAndEqualsPlugin.Enhance
295
    class Default implements AnnotationAppender {
296

297
        /**
298
         * The target onto which an annotation write process is to be applied.
299
         */
300
        private final Target target;
301

302
        /**
303
         * Creates a default annotation appender.
304
         *
305
         * @param target The target to which annotations are written to.
306
         */
307
        public Default(Target target) {
1✔
308
            this.target = target;
1✔
309
        }
1✔
310

311
        /**
312
         * Handles the writing of a single annotation to an annotation visitor.
313
         *
314
         * @param annotationVisitor     The annotation visitor the write process is to be applied on.
315
         * @param annotation            The annotation to be written.
316
         * @param annotationValueFilter The value filter to apply for discovering which values of an annotation should be written.
317
         */
318
        private static void handle(AnnotationVisitor annotationVisitor, AnnotationDescription annotation, AnnotationValueFilter annotationValueFilter) {
319
            for (MethodDescription.InDefinedShape methodDescription : annotation.getAnnotationType().getDeclaredMethods()) {
1✔
320
                if (annotationValueFilter.isRelevant(annotation, methodDescription)) {
1✔
321
                    apply(annotationVisitor, methodDescription.getReturnType().asErasure(), methodDescription.getName(), annotation.getValue(methodDescription).resolve());
1✔
322
                }
323
            }
1✔
324
            annotationVisitor.visitEnd();
1✔
325
        }
1✔
326

327
        /**
328
         * Performs the writing of a given annotation value to an annotation visitor.
329
         *
330
         * @param annotationVisitor The annotation visitor the write process is to be applied on.
331
         * @param valueType         The type of the annotation.
332
         * @param name              The name of the annotation type or {@code null} if no name is available.
333
         * @param value             The annotation's value.
334
         */
335
        public static void apply(AnnotationVisitor annotationVisitor, TypeDescription valueType, @MaybeNull String name, Object value) {
336
            if (valueType.isArray()) { // The Android emulator reads annotation arrays as annotation types. Therefore, this check needs to come first.
1✔
337
                AnnotationVisitor arrayVisitor = annotationVisitor.visitArray(name);
1✔
338
                int length = Array.getLength(value);
1✔
339
                TypeDescription componentType = valueType.getComponentType();
1✔
340
                for (int index = 0; index < length; index++) {
1✔
341
                    apply(arrayVisitor, componentType, NO_NAME, Array.get(value, index));
1✔
342
                }
343
                arrayVisitor.visitEnd();
1✔
344
            } else if (valueType.isAnnotation()) {
1✔
345
                handle(annotationVisitor.visitAnnotation(name, valueType.getDescriptor()), (AnnotationDescription) value, AnnotationValueFilter.Default.APPEND_DEFAULTS);
1✔
346
            } else if (valueType.isEnum()) {
1✔
347
                annotationVisitor.visitEnum(name, valueType.getDescriptor(), ((EnumerationDescription) value).getValue());
1✔
348
            } else if (valueType.represents(Class.class)) {
1✔
349
                annotationVisitor.visit(name, Type.getType(((TypeDescription) value).getDescriptor()));
1✔
350
            } else {
351
                annotationVisitor.visit(name, value);
1✔
352
            }
353
        }
1✔
354

355
        /**
356
         * {@inheritDoc}
357
         */
358
        public AnnotationAppender append(AnnotationDescription annotationDescription, AnnotationValueFilter annotationValueFilter) {
359
            switch (annotationDescription.getRetention()) {
1✔
360
                case RUNTIME:
361
                    doAppend(annotationDescription, true, annotationValueFilter);
1✔
362
                    break;
1✔
363
                case CLASS:
364
                    doAppend(annotationDescription, false, annotationValueFilter);
1✔
365
                    break;
1✔
366
                case SOURCE:
367
                    break;
1✔
368
                default:
369
                    throw new IllegalStateException("Unexpected retention policy: " + annotationDescription.getRetention());
×
370
            }
371
            return this;
1✔
372
        }
373

374
        /**
375
         * Tries to append a given annotation by reflectively reading an annotation.
376
         *
377
         * @param annotation            The annotation to be written.
378
         * @param visible               {@code true} if this annotation should be treated as visible at runtime.
379
         * @param annotationValueFilter The annotation value filter to apply.
380
         */
381
        private void doAppend(AnnotationDescription annotation, boolean visible, AnnotationValueFilter annotationValueFilter) {
382
            AnnotationVisitor annotationVisitor = target.visit(annotation.getAnnotationType().getDescriptor(), visible);
1✔
383
            if (annotationVisitor != null) {
1✔
384
                handle(annotationVisitor, annotation, annotationValueFilter);
1✔
385
            }
386
        }
1✔
387

388
        /**
389
         * {@inheritDoc}
390
         */
391
        public AnnotationAppender append(AnnotationDescription annotationDescription, AnnotationValueFilter annotationValueFilter, int typeReference, String typePath) {
392
            switch (annotationDescription.getRetention()) {
1✔
393
                case RUNTIME:
394
                    doAppend(annotationDescription, true, annotationValueFilter, typeReference, typePath);
1✔
395
                    break;
1✔
396
                case CLASS:
397
                    doAppend(annotationDescription, false, annotationValueFilter, typeReference, typePath);
1✔
398
                    break;
1✔
399
                case SOURCE:
400
                    break;
1✔
401
                default:
402
                    throw new IllegalStateException("Unexpected retention policy: " + annotationDescription.getRetention());
×
403
            }
404
            return this;
1✔
405
        }
406

407
        /**
408
         * Tries to append a given annotation by reflectively reading an annotation.
409
         *
410
         * @param annotation            The annotation to be written.
411
         * @param visible               {@code true} if this annotation should be treated as visible at runtime.
412
         * @param annotationValueFilter The annotation value filter to apply.
413
         * @param typeReference         The type annotation's type reference.
414
         * @param typePath              The type annotation's type path.
415
         */
416
        private void doAppend(AnnotationDescription annotation,
417
                              boolean visible,
418
                              AnnotationValueFilter annotationValueFilter,
419
                              int typeReference,
420
                              String typePath) {
421
            AnnotationVisitor annotationVisitor = target.visit(annotation.getAnnotationType().getDescriptor(), visible, typeReference, typePath);
1✔
422
            if (annotationVisitor != null) {
1✔
423
                handle(annotationVisitor, annotation, annotationValueFilter);
1✔
424
            }
425
        }
1✔
426
    }
427

428
    /**
429
     * A type visitor that visits all type annotations of a generic type and writes any discovered annotation to a
430
     * supplied {@link AnnotationAppender}.
431
     */
432
    @HashCodeAndEqualsPlugin.Enhance
433
    class ForTypeAnnotations implements TypeDescription.Generic.Visitor<AnnotationAppender> {
434

435
        /**
436
         * Indicates that type variables type annotations are written on a Java type.
437
         */
438
        public static final boolean VARIABLE_ON_TYPE = true;
439

440
        /**
441
         * Indicates that type variables type annotations are written on a Java method or constructor.
442
         */
443
        public static final boolean VARIABLE_ON_INVOKEABLE = false;
444

445
        /**
446
         * Represents an empty type path.
447
         */
448
        private static final String EMPTY_TYPE_PATH = "";
449

450
        /**
451
         * Represents a step to a component type within a type path.
452
         */
453
        private static final char COMPONENT_TYPE_PATH = '[';
454

455
        /**
456
         * Represents a wildcard type step within a type path.
457
         */
458
        private static final char WILDCARD_TYPE_PATH = '*';
459

460
        /**
461
         * Represents a (reversed) type step to an inner class within a type path.
462
         */
463
        private static final char INNER_CLASS_PATH = '.';
464

465
        /**
466
         * Represents an index type delimiter within a type path.
467
         */
468
        private static final char INDEXED_TYPE_DELIMITER = ';';
469

470
        /**
471
         * The index that indicates that super type type annotations are written onto a super class.
472
         */
473
        private static final int SUPER_CLASS_INDEX = -1;
474

475
        /**
476
         * The annotation appender to use.
477
         */
478
        private final AnnotationAppender annotationAppender;
479

480
        /**
481
         * The annotation value filter to use.
482
         */
483
        private final AnnotationValueFilter annotationValueFilter;
484

485
        /**
486
         * The type reference to use.
487
         */
488
        private final int typeReference;
489

490
        /**
491
         * The type path to use.
492
         */
493
        private final String typePath;
494

495
        /**
496
         * Creates a new type annotation appending visitor for an empty type path.
497
         *
498
         * @param annotationAppender    The annotation appender to use.
499
         * @param annotationValueFilter The annotation value filter to use.
500
         * @param typeReference         The type reference to use.
501
         */
502
        protected ForTypeAnnotations(AnnotationAppender annotationAppender, AnnotationValueFilter annotationValueFilter, TypeReference typeReference) {
503
            this(annotationAppender, annotationValueFilter, typeReference.getValue(), EMPTY_TYPE_PATH);
1✔
504
        }
1✔
505

506
        /**
507
         * Creates a new type annotation appending visitor.
508
         *
509
         * @param annotationAppender    The annotation appender to use.
510
         * @param annotationValueFilter The annotation value filter to use.
511
         * @param typeReference         The type reference to use.
512
         * @param typePath              The type path to use.
513
         */
514
        protected ForTypeAnnotations(AnnotationAppender annotationAppender, AnnotationValueFilter annotationValueFilter, int typeReference, String typePath) {
1✔
515
            this.annotationAppender = annotationAppender;
1✔
516
            this.annotationValueFilter = annotationValueFilter;
1✔
517
            this.typeReference = typeReference;
1✔
518
            this.typePath = typePath;
1✔
519
        }
1✔
520

521
        /**
522
         * Creates a type annotation appender for a type annotations of a super class type.
523
         *
524
         * @param annotationAppender    The annotation appender to write any type annotation to.
525
         * @param annotationValueFilter The annotation value filter to apply.
526
         * @return A visitor for appending type annotations of a super class.
527
         */
528
        public static TypeDescription.Generic.Visitor<AnnotationAppender> ofSuperClass(AnnotationAppender annotationAppender,
529
                                                                                       AnnotationValueFilter annotationValueFilter) {
530
            return new ForTypeAnnotations(annotationAppender, annotationValueFilter, TypeReference.newSuperTypeReference(SUPER_CLASS_INDEX));
1✔
531
        }
532

533
        /**
534
         * Creates a type annotation appender for type annotations of an interface type.
535
         *
536
         * @param annotationAppender    The annotation appender to write any type annotation to.
537
         * @param annotationValueFilter The annotation value filter to apply.
538
         * @param index                 The index of the interface type.
539
         * @return A visitor for appending type annotations of an interface type.
540
         */
541
        public static TypeDescription.Generic.Visitor<AnnotationAppender> ofInterfaceType(AnnotationAppender annotationAppender,
542
                                                                                          AnnotationValueFilter annotationValueFilter,
543
                                                                                          int index) {
544
            return new ForTypeAnnotations(annotationAppender, annotationValueFilter, TypeReference.newSuperTypeReference(index));
1✔
545
        }
546

547
        /**
548
         * Creates a type annotation appender for type annotations of a field's type.
549
         *
550
         * @param annotationAppender    The annotation appender to write any type annotation to.
551
         * @param annotationValueFilter The annotation value filter to apply.
552
         * @return A visitor for appending type annotations of a field's type.
553
         */
554
        public static TypeDescription.Generic.Visitor<AnnotationAppender> ofFieldType(AnnotationAppender annotationAppender,
555
                                                                                      AnnotationValueFilter annotationValueFilter) {
556
            return new ForTypeAnnotations(annotationAppender, annotationValueFilter, TypeReference.newTypeReference(TypeReference.FIELD));
1✔
557
        }
558

559
        /**
560
         * Creates a type annotation appender for type annotations of a method's return type.
561
         *
562
         * @param annotationAppender    The annotation appender to write any type annotation to.
563
         * @param annotationValueFilter The annotation value filter to apply.
564
         * @return A visitor for appending type annotations of a method's return type.
565
         */
566
        public static TypeDescription.Generic.Visitor<AnnotationAppender> ofMethodReturnType(AnnotationAppender annotationAppender,
567
                                                                                             AnnotationValueFilter annotationValueFilter) {
568
            return new ForTypeAnnotations(annotationAppender, annotationValueFilter, TypeReference.newTypeReference(TypeReference.METHOD_RETURN));
1✔
569
        }
570

571
        /**
572
         * Creates a type annotation appender for type annotations of a method's parameter type.
573
         *
574
         * @param annotationAppender    The annotation appender to write any type annotation to.
575
         * @param annotationValueFilter The annotation value filter to apply.
576
         * @param index                 The parameter index.
577
         * @return A visitor for appending type annotations of a method's parameter type.
578
         */
579
        public static TypeDescription.Generic.Visitor<AnnotationAppender> ofMethodParameterType(AnnotationAppender annotationAppender,
580
                                                                                                AnnotationValueFilter annotationValueFilter,
581
                                                                                                int index) {
582
            return new ForTypeAnnotations(annotationAppender, annotationValueFilter, TypeReference.newFormalParameterReference(index));
1✔
583
        }
584

585
        /**
586
         * Creates a type annotation appender for type annotations of a method's exception type.
587
         *
588
         * @param annotationAppender    The annotation appender to write any type annotation to.
589
         * @param annotationValueFilter The annotation value filter to apply.
590
         * @param index                 The exception type's index.
591
         * @return A visitor for appending type annotations of a method's exception type.
592
         */
593
        public static TypeDescription.Generic.Visitor<AnnotationAppender> ofExceptionType(AnnotationAppender annotationAppender,
594
                                                                                          AnnotationValueFilter annotationValueFilter,
595
                                                                                          int index) {
596
            return new ForTypeAnnotations(annotationAppender, annotationValueFilter, TypeReference.newExceptionReference(index));
1✔
597
        }
598

599
        /**
600
         * Creates a type annotation appender for type annotations of a method's receiver type.
601
         *
602
         * @param annotationAppender    The annotation appender to write any type annotation to.
603
         * @param annotationValueFilter The annotation value filter to apply.
604
         * @return A visitor for appending type annotations of a method's receiver type.
605
         */
606
        public static TypeDescription.Generic.Visitor<AnnotationAppender> ofReceiverType(AnnotationAppender annotationAppender,
607
                                                                                         AnnotationValueFilter annotationValueFilter) {
608
            return new ForTypeAnnotations(annotationAppender, annotationValueFilter, TypeReference.newTypeReference(TypeReference.METHOD_RECEIVER));
1✔
609
        }
610

611
        /**
612
         * Appends all supplied type variables to the supplied method appender.
613
         *
614
         * @param annotationAppender    The annotation appender to write any type annotation to.
615
         * @param annotationValueFilter The annotation value filter to apply.
616
         * @param variableOnType        {@code true} if the type variables are declared by a type, {@code false} if they are declared by a method.
617
         * @param typeVariables         The type variables to append.
618
         * @return The resulting annotation appender.
619
         */
620
        public static AnnotationAppender ofTypeVariable(AnnotationAppender annotationAppender,
621
                                                        AnnotationValueFilter annotationValueFilter,
622
                                                        boolean variableOnType,
623
                                                        List<? extends TypeDescription.Generic> typeVariables) {
624
            return ofTypeVariable(annotationAppender, annotationValueFilter, variableOnType, 0, typeVariables);
1✔
625
        }
626

627
        /**
628
         * Appends all supplied type variables to the supplied method appender.
629
         *
630
         * @param annotationAppender    The annotation appender to write any type annotation to.
631
         * @param annotationValueFilter The annotation value filter to apply.
632
         * @param variableOnType        {@code true} if the type variables are declared by a type, {@code false} if they are declared by a method.
633
         * @param subListIndex          The index of the first type variable to append. All previous type variables are ignored.
634
         * @param typeVariables         The type variables to append.
635
         * @return The resulting annotation appender.
636
         */
637
        public static AnnotationAppender ofTypeVariable(AnnotationAppender annotationAppender,
638
                                                        AnnotationValueFilter annotationValueFilter,
639
                                                        boolean variableOnType,
640
                                                        int subListIndex,
641
                                                        List<? extends TypeDescription.Generic> typeVariables) {
642
            int typeVariableIndex = subListIndex, variableBaseReference, variableBoundBaseBase;
1✔
643
            if (variableOnType) {
1✔
644
                variableBaseReference = TypeReference.CLASS_TYPE_PARAMETER;
1✔
645
                variableBoundBaseBase = TypeReference.CLASS_TYPE_PARAMETER_BOUND;
1✔
646
            } else {
647
                variableBaseReference = TypeReference.METHOD_TYPE_PARAMETER;
1✔
648
                variableBoundBaseBase = TypeReference.METHOD_TYPE_PARAMETER_BOUND;
1✔
649
            }
650
            for (TypeDescription.Generic typeVariable : typeVariables.subList(subListIndex, typeVariables.size())) {
1✔
651
                int typeReference = TypeReference.newTypeParameterReference(variableBaseReference, typeVariableIndex).getValue();
1✔
652
                for (AnnotationDescription annotationDescription : typeVariable.getDeclaredAnnotations()) {
1✔
653
                    annotationAppender = annotationAppender.append(annotationDescription, annotationValueFilter, typeReference, EMPTY_TYPE_PATH);
1✔
654
                }
1✔
655
                int boundIndex = !typeVariable.getUpperBounds().get(0).getSort().isTypeVariable() && typeVariable.getUpperBounds().get(0).isInterface()
1✔
656
                        ? 1
657
                        : 0;
658
                for (TypeDescription.Generic typeBound : typeVariable.getUpperBounds()) {
1✔
659
                    annotationAppender = typeBound.accept(new ForTypeAnnotations(annotationAppender,
1✔
660
                            annotationValueFilter,
661
                            TypeReference.newTypeParameterBoundReference(variableBoundBaseBase, typeVariableIndex, boundIndex++)));
1✔
662
                }
1✔
663
                typeVariableIndex++;
1✔
664
            }
1✔
665
            return annotationAppender;
1✔
666
        }
667

668
        /**
669
         * {@inheritDoc}
670
         */
671
        @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming component type for array type.")
672
        public AnnotationAppender onGenericArray(TypeDescription.Generic genericArray) {
673
            return genericArray.getComponentType().accept(new ForTypeAnnotations(apply(genericArray, typePath),
1✔
674
                    annotationValueFilter,
675
                    typeReference,
676
                    typePath + COMPONENT_TYPE_PATH));
677
        }
678

679
        /**
680
         * {@inheritDoc}
681
         */
682
        public AnnotationAppender onWildcard(TypeDescription.Generic wildcard) {
683
            TypeList.Generic lowerBounds = wildcard.getLowerBounds();
1✔
684
            return (lowerBounds.isEmpty()
1✔
685
                    ? wildcard.getUpperBounds().getOnly()
1✔
686
                    : lowerBounds.getOnly()).accept(new ForTypeAnnotations(apply(wildcard, typePath), annotationValueFilter, typeReference, typePath + WILDCARD_TYPE_PATH));
1✔
687
        }
688

689
        /**
690
         * {@inheritDoc}
691
         */
692
        public AnnotationAppender onParameterizedType(TypeDescription.Generic parameterizedType) {
693
            StringBuilder typePath = new StringBuilder(this.typePath);
1✔
694
            for (int index = 0; index < parameterizedType.asErasure().getInnerClassCount(); index++) {
1✔
695
                typePath = typePath.append(INNER_CLASS_PATH);
1✔
696
            }
697
            AnnotationAppender annotationAppender = apply(parameterizedType, typePath.toString());
1✔
698
            TypeDescription.Generic ownerType = parameterizedType.getOwnerType();
1✔
699
            if (ownerType != null) {
1✔
700
                annotationAppender = ownerType.accept(new ForTypeAnnotations(annotationAppender,
1✔
701
                        annotationValueFilter,
702
                        typeReference,
703
                        this.typePath));
704
            }
705
            int index = 0;
1✔
706
            for (TypeDescription.Generic typeArgument : parameterizedType.getTypeArguments()) {
1✔
707
                annotationAppender = typeArgument.accept(new ForTypeAnnotations(annotationAppender,
1✔
708
                        annotationValueFilter,
709
                        typeReference,
710
                        typePath.toString() + index++ + INDEXED_TYPE_DELIMITER));
1✔
711
            }
1✔
712
            return annotationAppender;
1✔
713
        }
714

715
        /**
716
         * {@inheritDoc}
717
         */
718
        public AnnotationAppender onTypeVariable(TypeDescription.Generic typeVariable) {
719
            return apply(typeVariable, typePath);
1✔
720
        }
721

722
        /**
723
         * {@inheritDoc}
724
         */
725
        public AnnotationAppender onNonGenericType(TypeDescription.Generic typeDescription) {
726
            StringBuilder typePath = new StringBuilder(this.typePath);
1✔
727
            for (int index = 0; index < typeDescription.asErasure().getInnerClassCount(); index++) {
1✔
728
                typePath = typePath.append(INNER_CLASS_PATH);
1✔
729
            }
730
            AnnotationAppender annotationAppender = apply(typeDescription, typePath.toString());
1✔
731
            TypeDescription.Generic componentType = typeDescription.getComponentType();
1✔
732
            if (componentType != null) {
1✔
733
                annotationAppender = componentType.accept(new ForTypeAnnotations(annotationAppender,
1✔
734
                        annotationValueFilter,
735
                        typeReference,
736
                        this.typePath + COMPONENT_TYPE_PATH)); // Impossible to be inner class
737
            }
738
            return annotationAppender;
1✔
739
        }
740

741
        /**
742
         * Writes all annotations of the supplied type to this instance's annotation appender.
743
         *
744
         * @param typeDescription The type of what all annotations should be written of.
745
         * @param typePath        The type path to use.
746
         * @return The resulting annotation appender.
747
         */
748
        private AnnotationAppender apply(TypeDescription.Generic typeDescription, String typePath) {
749
            AnnotationAppender annotationAppender = this.annotationAppender;
1✔
750
            for (AnnotationDescription annotationDescription : typeDescription.getDeclaredAnnotations()) {
1✔
751
                annotationAppender = annotationAppender.append(annotationDescription, annotationValueFilter, typeReference, typePath);
1✔
752
            }
1✔
753
            return annotationAppender;
1✔
754
        }
755
    }
756
}
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