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

raphw / byte-buddy / #752

20 Mar 2025 05:23PM UTC coverage: 85.175% (+0.005%) from 85.17%
#752

push

raphw
Add checksums

29243 of 34333 relevant lines covered (85.17%)

0.85 hits per line

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

98.23
/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/Transformer.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;
17

18
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
20
import net.bytebuddy.build.SafeVarargsPlugin;
21
import net.bytebuddy.description.annotation.AnnotationList;
22
import net.bytebuddy.description.annotation.AnnotationValue;
23
import net.bytebuddy.description.field.FieldDescription;
24
import net.bytebuddy.description.method.MethodDescription;
25
import net.bytebuddy.description.method.ParameterDescription;
26
import net.bytebuddy.description.method.ParameterList;
27
import net.bytebuddy.description.modifier.ModifierContributor;
28
import net.bytebuddy.description.type.TypeDefinition;
29
import net.bytebuddy.description.type.TypeDescription;
30
import net.bytebuddy.description.type.TypeList;
31
import net.bytebuddy.utility.nullability.MaybeNull;
32

33
import javax.annotation.Nonnull;
34
import java.util.ArrayList;
35
import java.util.Arrays;
36
import java.util.List;
37

38
import static net.bytebuddy.matcher.ElementMatchers.named;
39
import static net.bytebuddy.matcher.ElementMatchers.none;
40

41
/**
42
 * A transformer is responsible for transforming an object into a compatible instance of the same type.
43
 *
44
 * @param <T> The type of the instance being transformed.
45
 */
46
public interface Transformer<T> {
47

48
    /**
49
     * Transforms the supplied target.
50
     *
51
     * @param instrumentedType The instrumented type that declares the target being transformed.
52
     * @param target           The target entity that is being transformed.
53
     * @return The transformed instance.
54
     */
55
    T transform(TypeDescription instrumentedType, T target);
56

57
    /**
58
     * A non-operational transformer that returns the received instance.
59
     */
60
    enum NoOp implements Transformer<Object> {
1✔
61

62
        /**
63
         * The singleton instance.
64
         */
65
        INSTANCE;
1✔
66

67
        /**
68
         * Creates a transformer in a type-safe manner.
69
         *
70
         * @param <T> The type of the transformed object.
71
         * @return A non-operational transformer.
72
         */
73
        @SuppressWarnings("unchecked")
74
        public static <T> Transformer<T> make() {
75
            return (Transformer<T>) INSTANCE;
1✔
76
        }
77

78
        /**
79
         * {@inheritDoc}
80
         */
81
        public Object transform(TypeDescription instrumentedType, Object target) {
82
            return target;
1✔
83
        }
84
    }
85

86
    /**
87
     * A transformer for a field that delegates to another transformer that transforms a {@link net.bytebuddy.description.field.FieldDescription.Token}.
88
     */
89
    @HashCodeAndEqualsPlugin.Enhance
90
    class ForField implements Transformer<FieldDescription> {
91

92
        /**
93
         * The token transformer to apply to a transformed field.
94
         */
95
        private final Transformer<FieldDescription.Token> transformer;
96

97
        /**
98
         * Creates a new simple field transformer.
99
         *
100
         * @param transformer The token transformer to apply to a transformed field.
101
         */
102
        public ForField(Transformer<FieldDescription.Token> transformer) {
1✔
103
            this.transformer = transformer;
1✔
104
        }
1✔
105

106
        /**
107
         * Creates a field transformer that patches the transformed field by the given modifier contributors.
108
         *
109
         * @param modifierContributor The modifier contributors to apply.
110
         * @return A suitable field transformer.
111
         */
112
        public static Transformer<FieldDescription> withModifiers(ModifierContributor.ForField... modifierContributor) {
113
            return withModifiers(Arrays.asList(modifierContributor));
1✔
114
        }
115

116
        /**
117
         * Creates a field transformer that patches the transformed field by the given modifier contributors.
118
         *
119
         * @param modifierContributors The modifier contributors to apply.
120
         * @return A suitable field transformer.
121
         */
122
        public static Transformer<FieldDescription> withModifiers(List<? extends ModifierContributor.ForField> modifierContributors) {
123
            return new ForField(new FieldModifierTransformer(ModifierContributor.Resolver.of(modifierContributors)));
1✔
124
        }
125

126
        /**
127
         * {@inheritDoc}
128
         */
129
        @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Assuming declaring type for type member.")
130
        public FieldDescription transform(TypeDescription instrumentedType, FieldDescription fieldDescription) {
131
            return new TransformedField(instrumentedType,
1✔
132
                    fieldDescription.getDeclaringType(),
1✔
133
                    transformer.transform(instrumentedType, fieldDescription.asToken(none())),
1✔
134
                    fieldDescription.asDefined());
1✔
135
        }
136

137
        /**
138
         * A transformer for a field's modifiers.
139
         */
140
        @HashCodeAndEqualsPlugin.Enhance
141
        protected static class FieldModifierTransformer implements Transformer<FieldDescription.Token> {
142

143
            /**
144
             * The resolver to apply for transforming the modifiers of a field.
145
             */
146
            private final ModifierContributor.Resolver<ModifierContributor.ForField> resolver;
147

148
            /**
149
             * Creates a new field token modifier for transforming a field's modifiers.
150
             *
151
             * @param resolver The resolver to apply for transforming the modifiers of a field.
152
             */
153
            protected FieldModifierTransformer(ModifierContributor.Resolver<ModifierContributor.ForField> resolver) {
1✔
154
                this.resolver = resolver;
1✔
155
            }
1✔
156

157
            /**
158
             * {@inheritDoc}
159
             */
160
            public FieldDescription.Token transform(TypeDescription instrumentedType, FieldDescription.Token target) {
161
                return new FieldDescription.Token(target.getName(),
1✔
162
                        resolver.resolve(target.getModifiers()),
1✔
163
                        target.getType(),
1✔
164
                        target.getAnnotations());
1✔
165
            }
166
        }
167

168
        /**
169
         * An implementation of a transformed field.
170
         */
171
        protected static class TransformedField extends FieldDescription.AbstractBase {
172

173
            /**
174
             * The instrumented type for which this field is transformed.
175
             */
176
            private final TypeDescription instrumentedType;
177

178
            /**
179
             * The field's declaring type.
180
             */
181
            private final TypeDefinition declaringType;
182

183
            /**
184
             * A field token representing the transformed field.
185
             */
186
            private final FieldDescription.Token token;
187

188
            /**
189
             * The field's defined shape.
190
             */
191
            private final FieldDescription.InDefinedShape fieldDescription;
192

193
            /**
194
             * Creates a new transformed field.
195
             *
196
             * @param instrumentedType The instrumented type for which this field is transformed.
197
             * @param declaringType    The field's declaring type.
198
             * @param token            A field token representing the transformed field.
199
             * @param fieldDescription The field's defined shape.
200
             */
201
            protected TransformedField(TypeDescription instrumentedType,
202
                                       TypeDefinition declaringType,
203
                                       Token token,
204
                                       InDefinedShape fieldDescription) {
1✔
205
                this.instrumentedType = instrumentedType;
1✔
206
                this.declaringType = declaringType;
1✔
207
                this.token = token;
1✔
208
                this.fieldDescription = fieldDescription;
1✔
209
            }
1✔
210

211
            /**
212
             * {@inheritDoc}
213
             */
214
            public TypeDescription.Generic getType() {
215
                return token.getType().accept(TypeDescription.Generic.Visitor.Substitutor.ForAttachment.of(instrumentedType));
1✔
216
            }
217

218
            /**
219
             * {@inheritDoc}
220
             */
221
            public AnnotationList getDeclaredAnnotations() {
222
                return token.getAnnotations();
1✔
223
            }
224

225
            /**
226
             * {@inheritDoc}
227
             */
228
            @Nonnull
229
            public TypeDefinition getDeclaringType() {
230
                return declaringType;
1✔
231
            }
232

233
            /**
234
             * {@inheritDoc}
235
             */
236
            public int getModifiers() {
237
                return token.getModifiers();
1✔
238
            }
239

240
            /**
241
             * {@inheritDoc}
242
             */
243
            public InDefinedShape asDefined() {
244
                return fieldDescription;
1✔
245
            }
246

247
            /**
248
             * {@inheritDoc}
249
             */
250
            public String getName() {
251
                return token.getName();
1✔
252
            }
253
        }
254
    }
255

256
    /**
257
     * A transformer for a field that delegates to another transformer that transforms a {@link net.bytebuddy.description.method.MethodDescription.Token}.
258
     */
259
    @HashCodeAndEqualsPlugin.Enhance
260
    class ForMethod implements Transformer<MethodDescription> {
261

262
        /**
263
         * The transformer to be applied.
264
         */
265
        private final Transformer<MethodDescription.Token> transformer;
266

267
        /**
268
         * Creates a new transforming method transformer.
269
         *
270
         * @param transformer The transformer to be applied.
271
         */
272
        public ForMethod(Transformer<MethodDescription.Token> transformer) {
1✔
273
            this.transformer = transformer;
1✔
274
        }
1✔
275

276
        /**
277
         * Creates a transformer that enforces the supplied modifier contributors. All ranges of each contributor is first cleared and then overridden
278
         * by the specified modifiers in the order they are supplied.
279
         *
280
         * @param modifierContributor The modifier transformers in their application order.
281
         * @return A method transformer where each method's modifiers are adapted to the given modifiers.
282
         */
283
        public static Transformer<MethodDescription> withModifiers(ModifierContributor.ForMethod... modifierContributor) {
284
            return withModifiers(Arrays.asList(modifierContributor));
1✔
285
        }
286

287
        /**
288
         * Creates a transformer that enforces the supplied modifier contributors. All ranges of each contributor is first cleared and then overridden
289
         * by the specified modifiers in the order they are supplied.
290
         *
291
         * @param modifierContributors The modifier contributors in their application order.
292
         * @return A method transformer where each method's modifiers are adapted to the given modifiers.
293
         */
294
        public static Transformer<MethodDescription> withModifiers(List<? extends ModifierContributor.ForMethod> modifierContributors) {
295
            return new ForMethod(new MethodModifierTransformer(ModifierContributor.Resolver.of(modifierContributors)));
1✔
296
        }
297

298
        /**
299
         * {@inheritDoc}
300
         */
301
        public MethodDescription transform(TypeDescription instrumentedType, MethodDescription methodDescription) {
302
            return new TransformedMethod(instrumentedType,
1✔
303
                    methodDescription.getDeclaringType(),
1✔
304
                    transformer.transform(instrumentedType, methodDescription.asToken(none())),
1✔
305
                    methodDescription.asDefined());
1✔
306
        }
307

308
        /**
309
         * A transformer for a method's modifiers.
310
         */
311
        @HashCodeAndEqualsPlugin.Enhance
312
        protected static class MethodModifierTransformer implements Transformer<MethodDescription.Token> {
313

314
            /**
315
             * The resolver to apply onto the method's modifiers.
316
             */
317
            private final ModifierContributor.Resolver<ModifierContributor.ForMethod> resolver;
318

319
            /**
320
             * Creates a new modifier transformation.
321
             *
322
             * @param resolver The resolver to apply onto the method's modifiers.
323
             */
324
            protected MethodModifierTransformer(ModifierContributor.Resolver<ModifierContributor.ForMethod> resolver) {
1✔
325
                this.resolver = resolver;
1✔
326
            }
1✔
327

328
            /**
329
             * {@inheritDoc}
330
             */
331
            public MethodDescription.Token transform(TypeDescription instrumentedType, MethodDescription.Token target) {
332
                return new MethodDescription.Token(target.getName(),
1✔
333
                        resolver.resolve(target.getModifiers()),
1✔
334
                        target.getTypeVariableTokens(),
1✔
335
                        target.getReturnType(),
1✔
336
                        target.getParameterTokens(),
1✔
337
                        target.getExceptionTypes(),
1✔
338
                        target.getAnnotations(),
1✔
339
                        target.getDefaultValue(),
1✔
340
                        target.getReceiverType());
1✔
341
            }
342
        }
343

344
        /**
345
         * The transformed method.
346
         */
347
        protected static class TransformedMethod extends MethodDescription.AbstractBase {
348

349
            /**
350
             * The instrumented type for which this method is transformed.
351
             */
352
            private final TypeDescription instrumentedType;
353

354
            /**
355
             * The method's declaring type.
356
             */
357
            private final TypeDefinition declaringType;
358

359
            /**
360
             * The method representing the transformed method.
361
             */
362
            private final MethodDescription.Token token;
363

364
            /**
365
             * The defined shape of the transformed method.
366
             */
367
            private final MethodDescription.InDefinedShape methodDescription;
368

369
            /**
370
             * Creates a new transformed method.
371
             *
372
             * @param instrumentedType  The instrumented type for which this method is transformed.
373
             * @param declaringType     The method's declaring type.
374
             * @param token             The method representing the transformed method.
375
             * @param methodDescription The defined shape of the transformed method.
376
             */
377
            protected TransformedMethod(TypeDescription instrumentedType,
378
                                        TypeDefinition declaringType,
379
                                        Token token,
380
                                        InDefinedShape methodDescription) {
1✔
381
                this.instrumentedType = instrumentedType;
1✔
382
                this.declaringType = declaringType;
1✔
383
                this.token = token;
1✔
384
                this.methodDescription = methodDescription;
1✔
385
            }
1✔
386

387
            /**
388
             * {@inheritDoc}
389
             */
390
            public TypeList.Generic getTypeVariables() {
391
                return new TypeList.Generic.ForDetachedTypes.OfTypeVariables(this, token.getTypeVariableTokens(), new AttachmentVisitor());
1✔
392
            }
393

394
            /**
395
             * {@inheritDoc}
396
             */
397
            public TypeDescription.Generic getReturnType() {
398
                return token.getReturnType().accept(new AttachmentVisitor());
1✔
399
            }
400

401
            /**
402
             * {@inheritDoc}
403
             */
404
            public ParameterList<?> getParameters() {
405
                return new TransformedParameterList();
1✔
406
            }
407

408
            /**
409
             * {@inheritDoc}
410
             */
411
            public TypeList.Generic getExceptionTypes() {
412
                return new TypeList.Generic.ForDetachedTypes(token.getExceptionTypes(), new AttachmentVisitor());
1✔
413
            }
414

415
            /**
416
             * {@inheritDoc}
417
             */
418
            public AnnotationList getDeclaredAnnotations() {
419
                return token.getAnnotations();
1✔
420
            }
421

422
            /**
423
             * {@inheritDoc}
424
             */
425
            public String getInternalName() {
426
                return token.getName();
1✔
427
            }
428

429
            /**
430
             * {@inheritDoc}
431
             */
432
            @Nonnull
433
            public TypeDefinition getDeclaringType() {
434
                return declaringType;
1✔
435
            }
436

437
            /**
438
             * {@inheritDoc}
439
             */
440
            public int getModifiers() {
441
                return token.getModifiers();
1✔
442
            }
443

444
            /**
445
             * {@inheritDoc}
446
             */
447
            @MaybeNull
448
            public AnnotationValue<?, ?> getDefaultValue() {
449
                return token.getDefaultValue();
×
450
            }
451

452
            /**
453
             * {@inheritDoc}
454
             */
455
            public InDefinedShape asDefined() {
456
                return methodDescription;
1✔
457
            }
458

459
            /**
460
             * {@inheritDoc}
461
             */
462
            public TypeDescription.Generic getReceiverType() {
463
                TypeDescription.Generic receiverType = token.getReceiverType();
1✔
464
                return receiverType == null
1✔
465
                        ? TypeDescription.Generic.UNDEFINED
466
                        : receiverType.accept(new AttachmentVisitor());
1✔
467
            }
468

469
            /**
470
             * A parameter list representing the transformed method's parameters.
471
             */
472
            protected class TransformedParameterList extends ParameterList.AbstractBase<ParameterDescription> {
1✔
473

474
                /**
475
                 * {@inheritDoc}
476
                 */
477
                public ParameterDescription get(int index) {
478
                    return new TransformedParameter(index, token.getParameterTokens().get(index));
1✔
479
                }
480

481
                /**
482
                 * {@inheritDoc}
483
                 */
484
                public int size() {
485
                    return token.getParameterTokens().size();
1✔
486
                }
487
            }
488

489
            /**
490
             * A transformed method's parameter.
491
             */
492
            protected class TransformedParameter extends ParameterDescription.AbstractBase {
493

494
                /**
495
                 * The index of the transformed method.
496
                 */
497
                private final int index;
498

499
                /**
500
                 * The token representing the transformed method parameter's properties.
501
                 */
502
                private final ParameterDescription.Token parameterToken;
503

504
                /**
505
                 * Creates a transformed parameter.
506
                 *
507
                 * @param index          The index of the transformed method.
508
                 * @param parameterToken The token representing the transformed method parameter's properties.
509
                 */
510
                protected TransformedParameter(int index, ParameterDescription.Token parameterToken) {
1✔
511
                    this.index = index;
1✔
512
                    this.parameterToken = parameterToken;
1✔
513
                }
1✔
514

515
                /**
516
                 * {@inheritDoc}
517
                 */
518
                public TypeDescription.Generic getType() {
519
                    return parameterToken.getType().accept(new AttachmentVisitor());
1✔
520
                }
521

522
                /**
523
                 * {@inheritDoc}
524
                 */
525
                public MethodDescription getDeclaringMethod() {
526
                    return TransformedMethod.this;
1✔
527
                }
528

529
                /**
530
                 * {@inheritDoc}
531
                 */
532
                public int getIndex() {
533
                    return index;
1✔
534
                }
535

536
                /**
537
                 * {@inheritDoc}
538
                 */
539
                public boolean isNamed() {
540
                    return parameterToken.getName() != null;
1✔
541
                }
542

543
                /**
544
                 * {@inheritDoc}
545
                 */
546
                public boolean hasModifiers() {
547
                    return parameterToken.getModifiers() != null;
1✔
548
                }
549

550
                /**
551
                 * {@inheritDoc}
552
                 */
553
                public String getName() {
554
                    String name = parameterToken.getName();
1✔
555
                    return name == null
1✔
556
                            ? super.getName()
1✔
557
                            : name;
558
                }
559

560
                /**
561
                 * {@inheritDoc}
562
                 */
563
                public int getModifiers() {
564
                    Integer modifiers = parameterToken.getModifiers();
1✔
565
                    return modifiers == null
1✔
566
                            ? super.getModifiers()
1✔
567
                            : modifiers;
1✔
568
                }
569

570
                /**
571
                 * {@inheritDoc}
572
                 */
573
                public AnnotationList getDeclaredAnnotations() {
574
                    return parameterToken.getAnnotations();
1✔
575
                }
576

577
                /**
578
                 * {@inheritDoc}
579
                 */
580
                public InDefinedShape asDefined() {
581
                    return methodDescription.getParameters().get(index);
1✔
582
                }
583
            }
584

585
            /**
586
             * A visitor that attaches type variables based on the transformed method's type variables and the instrumented type. Binding type
587
             * variables directly for this method is not possible as type variables are already resolved for the instrumented type such
588
             * that it is required to bind variables for the instrumented type directly.
589
             */
590
            @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
591
            protected class AttachmentVisitor extends TypeDescription.Generic.Visitor.Substitutor.WithoutTypeSubstitution {
1✔
592

593
                /**
594
                 * {@inheritDoc}
595
                 */
596
                public TypeDescription.Generic onTypeVariable(TypeDescription.Generic typeVariable) {
597
                    TypeList.Generic candidates = getTypeVariables().filter(named(typeVariable.getSymbol()));
1✔
598
                    return new TypeDescription.Generic.OfTypeVariable.WithAnnotationOverlay(candidates.isEmpty()
1✔
599
                            ? instrumentedType.findExpectedVariable(typeVariable.getSymbol())
1✔
600
                            : candidates.getOnly(), typeVariable);
1✔
601
                }
602
            }
603
        }
604
    }
605

606
    /**
607
     * A compound transformer.
608
     *
609
     * @param <S> The type of the transformed instance.
610
     */
611
    @HashCodeAndEqualsPlugin.Enhance
612
    class Compound<S> implements Transformer<S> {
613

614
        /**
615
         * The list of transformers to apply in their application order.
616
         */
617
        private final List<Transformer<S>> transformers;
618

619
        /**
620
         * Creates a new compound transformer.
621
         *
622
         * @param transformer The list of transformers to apply in their application order.
623
         */
624
        @SafeVarargsPlugin.Enhance
625
        @SuppressWarnings("unchecked") // In absence of @SafeVarargs
626
        public Compound(Transformer<S>... transformer) {
627
            this(Arrays.asList(transformer));
1✔
628
        }
1✔
629

630
        /**
631
         * Creates a new compound transformer.
632
         *
633
         * @param transformers The list of transformers to apply in their application order.
634
         */
635
        public Compound(List<? extends Transformer<S>> transformers) {
1✔
636
            this.transformers = new ArrayList<Transformer<S>>();
1✔
637
            for (Transformer<S> transformer : transformers) {
1✔
638
                if (transformer instanceof Compound) {
1✔
639
                    this.transformers.addAll(((Compound<S>) transformer).transformers);
×
640
                } else if (!(transformer instanceof NoOp)) {
1✔
641
                    this.transformers.add(transformer);
1✔
642
                }
643
            }
1✔
644
        }
1✔
645

646
        /**
647
         * {@inheritDoc}
648
         */
649
        public S transform(TypeDescription instrumentedType, S target) {
650
            for (Transformer<S> transformer : transformers) {
1✔
651
                target = transformer.transform(instrumentedType, target);
1✔
652
            }
1✔
653
            return target;
1✔
654
        }
655
    }
656
}
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