1 /*
2 * Copyright 2014 - 2020 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.asm;
17
18 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19 import net.bytebuddy.description.field.FieldDescription;
20 import net.bytebuddy.description.field.FieldList;
21 import net.bytebuddy.description.method.MethodDescription;
22 import net.bytebuddy.description.method.MethodList;
23 import net.bytebuddy.description.type.TypeDescription;
24 import net.bytebuddy.implementation.Implementation;
25 import net.bytebuddy.matcher.ElementMatcher;
26 import net.bytebuddy.pool.TypePool;
27 import net.bytebuddy.utility.CompoundList;
28 import net.bytebuddy.utility.OpenedClassReader;
29 import net.bytebuddy.jar.asm.ClassVisitor;
30 import net.bytebuddy.jar.asm.FieldVisitor;
31 import net.bytebuddy.jar.asm.MethodVisitor;
32
33 import java.util.*;
34
35 import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
36 import static net.bytebuddy.matcher.ElementMatchers.isMethod;
37
38 /**
39 * A class visitor wrapper is used in order to register an intermediate ASM {@link net.bytebuddy.jar.asm.ClassVisitor} which
40 * is applied to the main type created by a {@link net.bytebuddy.dynamic.DynamicType.Builder} but not
41 * to any {@link net.bytebuddy.implementation.auxiliary.AuxiliaryType}s, if any.
42 */
43 public interface AsmVisitorWrapper {
44
45 /**
46 * Indicates that no flags should be set.
47 */
48 int NO_FLAGS = 0;
49
50 /**
51 * Defines the flags that are provided to any {@code ClassWriter} when writing a class. Typically, this gives opportunity to instruct ASM
52 * to compute stack map frames or the size of the local variables array and the operand stack. If no specific flags are required for
53 * applying this wrapper, the given value is to be returned.
54 *
55 * @param flags The currently set flags. This value should be combined (e.g. {@code flags | foo}) into the value that is returned by this wrapper.
56 * @return The flags to be provided to the ASM {@code ClassWriter}.
57 */
58 int mergeWriter(int flags);
59
60 /**
61 * Defines the flags that are provided to any {@code ClassReader} when reading a class if applicable. Typically, this gives opportunity to
62 * instruct ASM to expand or skip frames and to skip code and debug information. If no specific flags are required for applying this
63 * wrapper, the given value is to be returned.
64 *
65 * @param flags The currently set flags. This value should be combined (e.g. {@code flags | foo}) into the value that is returned by this wrapper.
66 * @return The flags to be provided to the ASM {@code ClassReader}.
67 */
68 int mergeReader(int flags);
69
70 /**
71 * Applies a {@code ClassVisitorWrapper} to the creation of a {@link net.bytebuddy.dynamic.DynamicType}.
72 *
73 * @param instrumentedType The instrumented type.
74 * @param classVisitor A {@code ClassVisitor} to become the new primary class visitor to which the created
75 * {@link net.bytebuddy.dynamic.DynamicType} is written to.
76 * @param implementationContext The implementation context of the current instrumentation.
77 * @param typePool The type pool that was provided for the class creation.
78 * @param fields The instrumented type's fields.
79 * @param methods The instrumented type's methods non-ignored declared and virtually inherited methods.
80 * @param writerFlags The ASM {@link net.bytebuddy.jar.asm.ClassWriter} flags to consider.
81 * @param readerFlags The ASM {@link net.bytebuddy.jar.asm.ClassReader} flags to consider.
82 * @return A new {@code ClassVisitor} that usually delegates to the {@code ClassVisitor} delivered in the argument.
83 */
84 ClassVisitor wrap(TypeDescription instrumentedType,
85 ClassVisitor classVisitor,
86 Implementation.Context implementationContext,
87 TypePool typePool,
88 FieldList<FieldDescription.InDefinedShape> fields,
89 MethodList<?> methods,
90 int writerFlags,
91 int readerFlags);
92
93 /**
94 * A class visitor wrapper that does not apply any changes.
95 */
96 enum NoOp implements AsmVisitorWrapper {
97
98 /**
99 * The singleton instance.
100 */
101 INSTANCE;
102
103 /**
104 * {@inheritDoc}
105 */
106 public int mergeWriter(int flags) {
107 return flags;
108 }
109
110 /**
111 * {@inheritDoc}
112 */
113 public int mergeReader(int flags) {
114 return flags;
115 }
116
117 /**
118 * {@inheritDoc}
119 */
120 public ClassVisitor wrap(TypeDescription instrumentedType,
121 ClassVisitor classVisitor,
122 Implementation.Context implementationContext,
123 TypePool typePool,
124 FieldList<FieldDescription.InDefinedShape> fields,
125 MethodList<?> methods,
126 int writerFlags,
127 int readerFlags) {
128 return classVisitor;
129 }
130 }
131
132 /**
133 * An abstract base implementation of an ASM visitor wrapper that does not set any flags.
134 */
135 abstract class AbstractBase implements AsmVisitorWrapper {
136
137 /**
138 * {@inheritDoc}
139 */
140 public int mergeWriter(int flags) {
141 return flags;
142 }
143
144 /**
145 * {@inheritDoc}
146 */
147 public int mergeReader(int flags) {
148 return flags;
149 }
150 }
151
152 /**
153 * An ASM visitor wrapper that allows to wrap declared fields of the instrumented type with a {@link FieldVisitorWrapper}.
154 */
155 @HashCodeAndEqualsPlugin.Enhance
156 class ForDeclaredFields extends AbstractBase {
157
158 /**
159 * The list of entries that describe matched fields in their application order.
160 */
161 private final List<Entry> entries;
162
163 /**
164 * Creates a new visitor wrapper for declared fields.
165 */
166 public ForDeclaredFields() {
167 this(Collections.<Entry>emptyList());
168 }
169
170 /**
171 * Creates a new visitor wrapper for declared fields.
172 *
173 * @param entries The list of entries that describe matched fields in their application order.
174 */
175 protected ForDeclaredFields(List<Entry> entries) {
176 this.entries = entries;
177 }
178
179 /**
180 * Defines a new field visitor wrapper to be applied if the given field matcher is matched. Previously defined
181 * entries are applied before the given matcher is applied.
182 *
183 * @param matcher The matcher to identify fields to be wrapped.
184 * @param fieldVisitorWrapper The field visitor wrapper to be applied if the given matcher is matched.
185 * @return A new ASM visitor wrapper that applied the given field visitor wrapper if the supplied matcher is matched.
186 */
187 public ForDeclaredFields field(ElementMatcher<? super FieldDescription.InDefinedShape> matcher, FieldVisitorWrapper... fieldVisitorWrapper) {
188 return field(matcher, Arrays.asList(fieldVisitorWrapper));
189 }
190
191 /**
192 * Defines a new field visitor wrapper to be applied if the given field matcher is matched. Previously defined
193 * entries are applied before the given matcher is applied.
194 *
195 * @param matcher The matcher to identify fields to be wrapped.
196 * @param fieldVisitorWrappers The field visitor wrapper to be applied if the given matcher is matched.
197 * @return A new ASM visitor wrapper that applied the given field visitor wrapper if the supplied matcher is matched.
198 */
199 public ForDeclaredFields field(ElementMatcher<? super FieldDescription.InDefinedShape> matcher, List<? extends FieldVisitorWrapper> fieldVisitorWrappers) {
200 return new ForDeclaredFields(CompoundList.of(entries, new Entry(matcher, fieldVisitorWrappers)));
201 }
202
203 /**
204 * {@inheritDoc}
205 */
206 public ClassVisitor wrap(TypeDescription instrumentedType,
207 ClassVisitor classVisitor,
208 Implementation.Context implementationContext,
209 TypePool typePool,
210 FieldList<FieldDescription.InDefinedShape> fields,
211 MethodList<?> methods,
212 int writerFlags,
213 int readerFlags) {
214 Map<String, FieldDescription.InDefinedShape> mapped = new HashMap<String, FieldDescription.InDefinedShape>();
215 for (FieldDescription.InDefinedShape fieldDescription : fields) {
216 mapped.put(fieldDescription.getInternalName() + fieldDescription.getDescriptor(), fieldDescription);
217 }
218 return new DispatchingVisitor(classVisitor, instrumentedType, mapped);
219 }
220
221 /**
222 * A field visitor wrapper that allows for wrapping a {@link FieldVisitor} defining a declared field.
223 */
224 public interface FieldVisitorWrapper {
225
226 /**
227 * Wraps a field visitor.
228 *
229 * @param instrumentedType The instrumented type.
230 * @param fieldDescription The field that is currently being defined.
231 * @param fieldVisitor The original field visitor that defines the given field.
232 * @return The wrapped field visitor.
233 */
234 FieldVisitor wrap(TypeDescription instrumentedType, FieldDescription.InDefinedShape fieldDescription, FieldVisitor fieldVisitor);
235 }
236
237 /**
238 * An entry describing a field visitor wrapper paired with a matcher for fields to be wrapped.
239 */
240 @HashCodeAndEqualsPlugin.Enhance
241 protected static class Entry implements ElementMatcher<FieldDescription.InDefinedShape>, FieldVisitorWrapper {
242
243 /**
244 * The matcher to identify fields to be wrapped.
245 */
246 private final ElementMatcher<? super FieldDescription.InDefinedShape> matcher;
247
248 /**
249 * The field visitor wrapper to be applied if the given matcher is matched.
250 */
251 private final List<? extends FieldVisitorWrapper> fieldVisitorWrappers;
252
253 /**
254 * Creates a new entry.
255 *
256 * @param matcher The matcher to identify fields to be wrapped.
257 * @param fieldVisitorWrappers The field visitor wrapper to be applied if the given matcher is matched.
258 */
259 protected Entry(ElementMatcher<? super FieldDescription.InDefinedShape> matcher, List<? extends FieldVisitorWrapper> fieldVisitorWrappers) {
260 this.matcher = matcher;
261 this.fieldVisitorWrappers = fieldVisitorWrappers;
262 }
263
264 /**
265 * {@inheritDoc}
266 */
267 public boolean matches(FieldDescription.InDefinedShape target) {
268 return target != null && matcher.matches(target);
269 }
270
271 /**
272 * {@inheritDoc}
273 */
274 public FieldVisitor wrap(TypeDescription instrumentedType, FieldDescription.InDefinedShape fieldDescription, FieldVisitor fieldVisitor) {
275 for (FieldVisitorWrapper fieldVisitorWrapper : fieldVisitorWrappers) {
276 fieldVisitor = fieldVisitorWrapper.wrap(instrumentedType, fieldDescription, fieldVisitor);
277 }
278 return fieldVisitor;
279 }
280 }
281
282 /**
283 * A class visitor that applies the outer ASM visitor for identifying declared fields.
284 */
285 protected class DispatchingVisitor extends ClassVisitor {
286
287 /**
288 * The instrumented type.
289 */
290 private final TypeDescription instrumentedType;
291
292 /**
293 * A mapping of fields by their name and descriptor key-combination.
294 */
295 private final Map<String, FieldDescription.InDefinedShape> fields;
296
297 /**
298 * Creates a new dispatching visitor.
299 *
300 * @param classVisitor The underlying class visitor.
301 * @param instrumentedType The instrumented type.
302 * @param fields The instrumented type's declared fields.
303 */
304 protected DispatchingVisitor(ClassVisitor classVisitor, TypeDescription instrumentedType, Map<String, FieldDescription.InDefinedShape> fields) {
305 super(OpenedClassReader.ASM_API, classVisitor);
306 this.instrumentedType = instrumentedType;
307 this.fields = fields;
308 }
309
310 @Override
311 public FieldVisitor visitField(int modifiers, String internalName, String descriptor, String signature, Object defaultValue) {
312 FieldVisitor fieldVisitor = super.visitField(modifiers, internalName, descriptor, signature, defaultValue);
313 FieldDescription.InDefinedShape fieldDescription = fields.get(internalName + descriptor);
314 if (fieldVisitor != null && fieldDescription != null) {
315 for (Entry entry : entries) {
316 if (entry.matches(fieldDescription)) {
317 fieldVisitor = entry.wrap(instrumentedType, fieldDescription, fieldVisitor);
318 }
319 }
320 }
321 return fieldVisitor;
322 }
323 }
324 }
325
326 /**
327 * <p>
328 * An ASM visitor wrapper that allows to wrap <b>declared methods</b> of the instrumented type with a {@link MethodVisitorWrapper}.
329 * </p>
330 * <p>
331 * Note: Inherited methods are <b>not</b> matched by this visitor, even if they are intercepted by a normal interception.
332 * </p>
333 */
334 @HashCodeAndEqualsPlugin.Enhance
335 class ForDeclaredMethods implements AsmVisitorWrapper {
336
337 /**
338 * The list of entries that describe matched methods in their application order.
339 */
340 private final List<Entry> entries;
341
342 /**
343 * The writer flags to set.
344 */
345 private final int writerFlags;
346
347 /**
348 * The reader flags to set.
349 */
350 private final int readerFlags;
351
352 /**
353 * Creates a new visitor wrapper for declared methods.
354 */
355 public ForDeclaredMethods() {
356 this(Collections.<Entry>emptyList(), NO_FLAGS, NO_FLAGS);
357 }
358
359 /**
360 * Creates a new visitor wrapper for declared methods.
361 *
362 * @param entries The list of entries that describe matched methods in their application order.
363 * @param readerFlags The reader flags to set.
364 * @param writerFlags The writer flags to set.
365 */
366 protected ForDeclaredMethods(List<Entry> entries, int writerFlags, int readerFlags) {
367 this.entries = entries;
368 this.writerFlags = writerFlags;
369 this.readerFlags = readerFlags;
370 }
371
372 /**
373 * Defines a new method visitor wrapper to be applied on any method if the given method matcher is matched.
374 * Previously defined entries are applied before the given matcher is applied.
375 *
376 * @param matcher The matcher to identify methods to be wrapped.
377 * @param methodVisitorWrapper The method visitor wrapper to be applied if the given matcher is matched.
378 * @return A new ASM visitor wrapper that applied the given method visitor wrapper if the supplied matcher is matched.
379 */
380 public ForDeclaredMethods method(ElementMatcher<? super MethodDescription> matcher, MethodVisitorWrapper... methodVisitorWrapper) {
381 return method(matcher, Arrays.asList(methodVisitorWrapper));
382 }
383
384 /**
385 * Defines a new method visitor wrapper to be applied on any method if the given method matcher is matched.
386 * Previously defined entries are applied before the given matcher is applied.
387 *
388 * @param matcher The matcher to identify methods to be wrapped.
389 * @param methodVisitorWrappers The method visitor wrapper to be applied if the given matcher is matched.
390 * @return A new ASM visitor wrapper that applied the given method visitor wrapper if the supplied matcher is matched.
391 */
392 public ForDeclaredMethods method(ElementMatcher<? super MethodDescription> matcher, List<? extends MethodVisitorWrapper> methodVisitorWrappers) {
393 return invokable(isMethod().and(matcher), methodVisitorWrappers);
394 }
395
396 /**
397 * Defines a new method visitor wrapper to be applied on any constructor if the given method matcher is matched.
398 * Previously defined entries are applied before the given matcher is applied.
399 *
400 * @param matcher The matcher to identify constructors to be wrapped.
401 * @param methodVisitorWrapper The method visitor wrapper to be applied if the given matcher is matched.
402 * @return A new ASM visitor wrapper that applied the given method visitor wrapper if the supplied matcher is matched.
403 */
404 public ForDeclaredMethods constructor(ElementMatcher<? super MethodDescription> matcher, MethodVisitorWrapper... methodVisitorWrapper) {
405 return constructor(matcher, Arrays.asList(methodVisitorWrapper));
406 }
407
408 /**
409 * Defines a new method visitor wrapper to be applied on any constructor if the given method matcher is matched.
410 * Previously defined entries are applied before the given matcher is applied.
411 *
412 * @param matcher The matcher to identify constructors to be wrapped.
413 * @param methodVisitorWrappers The method visitor wrapper to be applied if the given matcher is matched.
414 * @return A new ASM visitor wrapper that applied the given method visitor wrapper if the supplied matcher is matched.
415 */
416 public ForDeclaredMethods constructor(ElementMatcher<? super MethodDescription> matcher, List<? extends MethodVisitorWrapper> methodVisitorWrappers) {
417 return invokable(isConstructor().and(matcher), methodVisitorWrappers);
418 }
419
420 /**
421 * Defines a new method visitor wrapper to be applied on any method or constructor if the given method matcher is matched.
422 * Previously defined entries are applied before the given matcher is applied.
423 *
424 * @param matcher The matcher to identify methods or constructors to be wrapped.
425 * @param methodVisitorWrapper The method visitor wrapper to be applied if the given matcher is matched.
426 * @return A new ASM visitor wrapper that applied the given method visitor wrapper if the supplied matcher is matched.
427 */
428 public ForDeclaredMethods invokable(ElementMatcher<? super MethodDescription> matcher, MethodVisitorWrapper... methodVisitorWrapper) {
429 return invokable(matcher, Arrays.asList(methodVisitorWrapper));
430 }
431
432 /**
433 * Defines a new method visitor wrapper to be applied on any method or constructor if the given method matcher is matched.
434 * Previously defined entries are applied before the given matcher is applied.
435 *
436 * @param matcher The matcher to identify methods or constructors to be wrapped.
437 * @param methodVisitorWrappers The method visitor wrapper to be applied if the given matcher is matched.
438 * @return A new ASM visitor wrapper that applied the given method visitor wrapper if the supplied matcher is matched.
439 */
440 public ForDeclaredMethods invokable(ElementMatcher<? super MethodDescription> matcher, List<? extends MethodVisitorWrapper> methodVisitorWrappers) {
441 return new ForDeclaredMethods(CompoundList.of(entries, new Entry(matcher, methodVisitorWrappers)), writerFlags, readerFlags);
442 }
443
444 /**
445 * Sets flags for the {@link net.bytebuddy.jar.asm.ClassWriter} this wrapper is applied to.
446 *
447 * @param flags The flags to set for the {@link net.bytebuddy.jar.asm.ClassWriter}.
448 * @return A new ASM visitor wrapper that sets the supplied writer flags.
449 */
450 public ForDeclaredMethods writerFlags(int flags) {
451 return new ForDeclaredMethods(entries, writerFlags | flags, readerFlags);
452 }
453
454 /**
455 * Sets flags for the {@link net.bytebuddy.jar.asm.ClassReader} this wrapper is applied to.
456 *
457 * @param flags The flags to set for the {@link net.bytebuddy.jar.asm.ClassReader}.
458 * @return A new ASM visitor wrapper that sets the supplied reader flags.
459 */
460 public ForDeclaredMethods readerFlags(int flags) {
461 return new ForDeclaredMethods(entries, writerFlags, readerFlags | flags);
462 }
463
464 /**
465 * {@inheritDoc}
466 */
467 public int mergeWriter(int flags) {
468 return flags | writerFlags;
469 }
470
471 /**
472 * {@inheritDoc}
473 */
474 public int mergeReader(int flags) {
475 return flags | readerFlags;
476 }
477
478 /**
479 * {@inheritDoc}
480 */
481 public ClassVisitor wrap(TypeDescription instrumentedType,
482 ClassVisitor classVisitor,
483 Implementation.Context implementationContext,
484 TypePool typePool,
485 FieldList<FieldDescription.InDefinedShape> fields,
486 MethodList<?> methods,
487 int writerFlags,
488 int readerFlags) {
489 Map<String, MethodDescription> mapped = new HashMap<String, MethodDescription>();
490 for (MethodDescription methodDescription : CompoundList.<MethodDescription>of(methods, new MethodDescription.Latent.TypeInitializer(instrumentedType))) {
491 mapped.put(methodDescription.getInternalName() + methodDescription.getDescriptor(), methodDescription);
492 }
493 return new DispatchingVisitor(classVisitor,
494 instrumentedType,
495 implementationContext,
496 typePool,
497 mapped,
498 writerFlags,
499 readerFlags);
500 }
501
502 /**
503 * A method visitor wrapper that allows for wrapping a {@link MethodVisitor} defining a declared method.
504 */
505 public interface MethodVisitorWrapper {
506
507 /**
508 * Wraps a method visitor.
509 *
510 * @param instrumentedType The instrumented type.
511 * @param instrumentedMethod The method that is currently being defined.
512 * @param methodVisitor The original field visitor that defines the given method.
513 * @param implementationContext The implementation context to use.
514 * @param typePool The type pool to use.
515 * @param writerFlags The ASM {@link net.bytebuddy.jar.asm.ClassWriter} reader flags to consider.
516 * @param readerFlags The ASM {@link net.bytebuddy.jar.asm.ClassReader} reader flags to consider.
517 * @return The wrapped method visitor.
518 */
519 MethodVisitor wrap(TypeDescription instrumentedType,
520 MethodDescription instrumentedMethod,
521 MethodVisitor methodVisitor,
522 Implementation.Context implementationContext,
523 TypePool typePool,
524 int writerFlags,
525 int readerFlags);
526 }
527
528 /**
529 * An entry describing a method visitor wrapper paired with a matcher for fields to be wrapped.
530 */
531 @HashCodeAndEqualsPlugin.Enhance
532 protected static class Entry implements ElementMatcher<MethodDescription>, MethodVisitorWrapper {
533
534 /**
535 * The matcher to identify methods to be wrapped.
536 */
537 private final ElementMatcher<? super MethodDescription> matcher;
538
539 /**
540 * The method visitor wrapper to be applied if the given matcher is matched.
541 */
542 private final List<? extends MethodVisitorWrapper> methodVisitorWrappers;
543
544 /**
545 * Creates a new entry.
546 *
547 * @param matcher The matcher to identify methods to be wrapped.
548 * @param methodVisitorWrappers The method visitor wrapper to be applied if the given matcher is matched.
549 */
550 protected Entry(ElementMatcher<? super MethodDescription> matcher, List<? extends MethodVisitorWrapper> methodVisitorWrappers) {
551 this.matcher = matcher;
552 this.methodVisitorWrappers = methodVisitorWrappers;
553 }
554
555 /**
556 * {@inheritDoc}
557 */
558 public boolean matches(MethodDescription target) {
559 return target != null && matcher.matches(target);
560 }
561
562 /**
563 * {@inheritDoc}
564 */
565 public MethodVisitor wrap(TypeDescription instrumentedType,
566 MethodDescription instrumentedMethod,
567 MethodVisitor methodVisitor,
568 Implementation.Context implementationContext,
569 TypePool typePool,
570 int writerFlags,
571 int readerFlags) {
572 for (MethodVisitorWrapper methodVisitorWrapper : methodVisitorWrappers) {
573 methodVisitor = methodVisitorWrapper.wrap(instrumentedType,
574 instrumentedMethod,
575 methodVisitor,
576 implementationContext,
577 typePool,
578 writerFlags,
579 readerFlags);
580 }
581 return methodVisitor;
582 }
583 }
584
585 /**
586 * A class visitor that applies the outer ASM visitor for identifying declared methods.
587 */
588 protected class DispatchingVisitor extends ClassVisitor {
589
590 /**
591 * The instrumented type.
592 */
593 private final TypeDescription instrumentedType;
594
595 /**
596 * The implementation context to use.
597 */
598 private final Implementation.Context implementationContext;
599
600 /**
601 * The type pool to use.
602 */
603 private final TypePool typePool;
604
605 /**
606 * The ASM {@link net.bytebuddy.jar.asm.ClassWriter} reader flags to consider.
607 */
608 private final int writerFlags;
609
610 /**
611 * The ASM {@link net.bytebuddy.jar.asm.ClassReader} reader flags to consider.
612 */
613 private final int readerFlags;
614
615 /**
616 * A mapping of fields by their name.
617 */
618 private final Map<String, MethodDescription> methods;
619
620 /**
621 * Creates a new dispatching visitor.
622 *
623 * @param classVisitor The underlying class visitor.
624 * @param instrumentedType The instrumented type.
625 * @param implementationContext The implementation context to use.
626 * @param typePool The type pool to use.
627 * @param methods The methods that are declared by the instrumented type or virtually inherited.
628 * @param writerFlags The ASM {@link net.bytebuddy.jar.asm.ClassWriter} flags to consider.
629 * @param readerFlags The ASM {@link net.bytebuddy.jar.asm.ClassReader} flags to consider.
630 */
631 protected DispatchingVisitor(ClassVisitor classVisitor,
632 TypeDescription instrumentedType,
633 Implementation.Context implementationContext,
634 TypePool typePool,
635 Map<String, MethodDescription> methods,
636 int writerFlags,
637 int readerFlags) {
638 super(OpenedClassReader.ASM_API, classVisitor);
639 this.instrumentedType = instrumentedType;
640 this.implementationContext = implementationContext;
641 this.typePool = typePool;
642 this.methods = methods;
643 this.writerFlags = writerFlags;
644 this.readerFlags = readerFlags;
645 }
646
647 @Override
648 public MethodVisitor visitMethod(int modifiers, String internalName, String descriptor, String signature, String[] exceptions) {
649 MethodVisitor methodVisitor = super.visitMethod(modifiers, internalName, descriptor, signature, exceptions);
650 MethodDescription methodDescription = methods.get(internalName + descriptor);
651 if (methodVisitor != null && methodDescription != null) {
652 for (Entry entry : entries) {
653 if (entry.matches(methodDescription)) {
654 methodVisitor = entry.wrap(instrumentedType,
655 methodDescription,
656 methodVisitor,
657 implementationContext,
658 typePool,
659 writerFlags,
660 readerFlags);
661 }
662 }
663 }
664 return methodVisitor;
665 }
666 }
667 }
668
669 /**
670 * An ordered, immutable chain of {@link AsmVisitorWrapper}s.
671 */
672 @HashCodeAndEqualsPlugin.Enhance
673 class Compound implements AsmVisitorWrapper {
674
675 /**
676 * The class visitor wrappers that are represented by this chain in their order. This list must not be mutated.
677 */
678 private final List<AsmVisitorWrapper> asmVisitorWrappers;
679
680 /**
681 * Creates a new immutable chain based on an existing list of {@link AsmVisitorWrapper}s
682 * where no copy of the received array is made.
683 *
684 * @param asmVisitorWrapper An array of {@link AsmVisitorWrapper}s where elements
685 * at the beginning of the list are applied first, i.e. will be at the bottom of the generated
686 * {@link net.bytebuddy.jar.asm.ClassVisitor}.
687 */
688 public Compound(AsmVisitorWrapper... asmVisitorWrapper) {
689 this(Arrays.asList(asmVisitorWrapper));
690 }
691
692 /**
693 * Creates a new immutable chain based on an existing list of {@link AsmVisitorWrapper}s
694 * where no copy of the received list is made.
695 *
696 * @param asmVisitorWrappers A list of {@link AsmVisitorWrapper}s where elements
697 * at the beginning of the list are applied first, i.e. will be at the bottom of the generated
698 * {@link net.bytebuddy.jar.asm.ClassVisitor}.
699 */
700 public Compound(List<? extends AsmVisitorWrapper> asmVisitorWrappers) {
701 this.asmVisitorWrappers = new ArrayList<AsmVisitorWrapper>();
702 for (AsmVisitorWrapper asmVisitorWrapper : asmVisitorWrappers) {
703 if (asmVisitorWrapper instanceof Compound) {
704 this.asmVisitorWrappers.addAll(((Compound) asmVisitorWrapper).asmVisitorWrappers);
705 } else if (!(asmVisitorWrapper instanceof NoOp)) {
706 this.asmVisitorWrappers.add(asmVisitorWrapper);
707 }
708 }
709 }
710
711 /**
712 * {@inheritDoc}
713 */
714 public int mergeWriter(int flags) {
715 for (AsmVisitorWrapper asmVisitorWrapper : asmVisitorWrappers) {
716 flags = asmVisitorWrapper.mergeWriter(flags);
717 }
718 return flags;
719 }
720
721 /**
722 * {@inheritDoc}
723 */
724 public int mergeReader(int flags) {
725 for (AsmVisitorWrapper asmVisitorWrapper : asmVisitorWrappers) {
726 flags = asmVisitorWrapper.mergeReader(flags);
727 }
728 return flags;
729 }
730
731 /**
732 * {@inheritDoc}
733 */
734 public ClassVisitor wrap(TypeDescription instrumentedType,
735 ClassVisitor classVisitor,
736 Implementation.Context implementationContext,
737 TypePool typePool,
738 FieldList<FieldDescription.InDefinedShape> fields,
739 MethodList<?> methods,
740 int writerFlags,
741 int readerFlags) {
742 for (AsmVisitorWrapper asmVisitorWrapper : asmVisitorWrappers) {
743 classVisitor = asmVisitorWrapper.wrap(instrumentedType,
744 classVisitor,
745 implementationContext,
746 typePool,
747 fields,
748 methods,
749 writerFlags,
750 readerFlags);
751 }
752 return classVisitor;
753 }
754 }
755 }
756