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