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.implementation;
17
18 import net.bytebuddy.ClassFileVersion;
19 import net.bytebuddy.build.CachedReturnPlugin;
20 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
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.Visibility;
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.dynamic.DynamicType;
32 import net.bytebuddy.dynamic.scaffold.InstrumentedType;
33 import net.bytebuddy.dynamic.scaffold.MethodGraph;
34 import net.bytebuddy.dynamic.scaffold.TypeInitializer;
35 import net.bytebuddy.dynamic.scaffold.TypeWriter;
36 import net.bytebuddy.implementation.attribute.AnnotationValueFilter;
37 import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
38 import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
39 import net.bytebuddy.implementation.bytecode.StackManipulation;
40 import net.bytebuddy.implementation.bytecode.member.FieldAccess;
41 import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
42 import net.bytebuddy.implementation.bytecode.member.MethodReturn;
43 import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
44 import net.bytebuddy.utility.CompoundList;
45 import net.bytebuddy.utility.RandomString;
46 import net.bytebuddy.jar.asm.ClassVisitor;
47 import net.bytebuddy.jar.asm.FieldVisitor;
48 import net.bytebuddy.jar.asm.MethodVisitor;
49 import net.bytebuddy.jar.asm.Opcodes;
50
51 import java.util.*;
52
53 /**
54 * An implementation is responsible for implementing methods of a dynamically created type as byte code. An
55 * implementation is applied in two stages:
56 * <ol>
57 * <li>The implementation is able to prepare an instrumented type by adding fields and/or helper methods that are
58 * required for the methods implemented by this implementation. Furthermore,
59 * {@link LoadedTypeInitializer}s and byte code for the type initializer can be registered for the instrumented
60 * type.</li>
61 * <li>Any implementation is required to supply a byte code appender that is responsible for providing the byte code
62 * to the instrumented methods that were delegated to this implementation. This byte code appender is also
63 * be responsible for providing implementations for the methods added in step <i>1</i>.</li>
64 * </ol>
65 * <p> </p>
66 * An implementation should provide meaningful implementations of both {@link java.lang.Object#equals(Object)}
67 * and {@link Object#hashCode()} if it wants to avoid to be used twice within the creation of a dynamic type. For two
68 * equal implementations only one will be applied on the creation of a dynamic type.
69 */
70 public interface Implementation extends InstrumentedType.Prepareable {
71
72 /**
73 * Creates a byte code appender that determines the implementation of the instrumented type's methods.
74 *
75 * @param implementationTarget The target of the current implementation.
76 * @return A byte code appender for implementing methods delegated to this implementation. This byte code appender
77 * is also responsible for handling methods that were added by this implementation on the call to
78 * {@link Implementation#prepare(InstrumentedType)}.
79 */
80 ByteCodeAppender appender(Target implementationTarget);
81
82 /**
83 * Represents an implementation that can be chained together with another implementation.
84 */
85 interface Composable extends Implementation {
86
87 /**
88 * Appends the supplied implementation to this implementation.
89 *
90 * @param implementation The subsequent implementation.
91 * @return An implementation that combines this implementation with the provided one.
92 */
93 Implementation andThen(Implementation implementation);
94
95 /**
96 * Appends the supplied composable implementation to this implementation.
97 *
98 * @param implementation The subsequent composable implementation.
99 * @return A composable implementation that combines this implementation with the provided one.
100 */
101 Composable andThen(Composable implementation);
102 }
103
104 /**
105 * Represents an type-specific method invocation on the current instrumented type which is not legal from outside
106 * the type such as a super method or default method invocation. Legal instances of special method invocations must
107 * be equal to one another if they represent the same invocation target.
108 */
109 interface SpecialMethodInvocation extends StackManipulation {
110
111 /**
112 * Returns the method that represents this special method invocation. This method can be different even for
113 * equal special method invocations, dependant on the method that was used to request such an invocation by the
114 * means of a {@link Implementation.Target}.
115 *
116 * @return The method description that describes this instances invocation target.
117 */
118 MethodDescription getMethodDescription();
119
120 /**
121 * Returns the target type the represented method is invoked on.
122 *
123 * @return The type the represented method is invoked on.
124 */
125 TypeDescription getTypeDescription();
126
127 /**
128 * Checks that this special method invocation is compatible with the supplied type representation.
129 *
130 * @param token The type token to check against.
131 * @return This special method invocation or an illegal invocation if the method invocation is not applicable.
132 */
133 SpecialMethodInvocation withCheckedCompatibilityTo(MethodDescription.TypeToken token);
134
135 /**
136 * A canonical implementation of an illegal {@link Implementation.SpecialMethodInvocation}.
137 */
138 enum Illegal implements SpecialMethodInvocation {
139
140 /**
141 * The singleton instance.
142 */
143 INSTANCE;
144
145 /**
146 * {@inheritDoc}
147 */
148 public boolean isValid() {
149 return false;
150 }
151
152 /**
153 * {@inheritDoc}
154 */
155 public Size apply(MethodVisitor methodVisitor, Context implementationContext) {
156 throw new IllegalStateException("Cannot implement an undefined method");
157 }
158
159 /**
160 * {@inheritDoc}
161 */
162 public MethodDescription getMethodDescription() {
163 throw new IllegalStateException("An illegal special method invocation must not be applied");
164 }
165
166 /**
167 * {@inheritDoc}
168 */
169 public TypeDescription getTypeDescription() {
170 throw new IllegalStateException("An illegal special method invocation must not be applied");
171 }
172
173 /**
174 * {@inheritDoc}
175 */
176 public SpecialMethodInvocation withCheckedCompatibilityTo(MethodDescription.TypeToken token) {
177 return this;
178 }
179 }
180
181 /**
182 * An abstract base implementation of a valid special method invocation.
183 */
184 abstract class AbstractBase implements SpecialMethodInvocation {
185
186 /**
187 * {@inheritDoc}
188 */
189 public boolean isValid() {
190 return true;
191 }
192
193 @Override
194 @CachedReturnPlugin.Enhance
195 public int hashCode() {
196 return 31 * getMethodDescription().asSignatureToken().hashCode() + getTypeDescription().hashCode();
197 }
198
199 @Override
200 public boolean equals(Object other) {
201 if (this == other) {
202 return true;
203 } else if (!(other instanceof SpecialMethodInvocation)) {
204 return false;
205 }
206 SpecialMethodInvocation specialMethodInvocation = (SpecialMethodInvocation) other;
207 return getMethodDescription().asSignatureToken().equals(specialMethodInvocation.getMethodDescription().asSignatureToken())
208 && getTypeDescription().equals(specialMethodInvocation.getTypeDescription());
209 }
210 }
211
212 /**
213 * A canonical implementation of a {@link SpecialMethodInvocation}.
214 */
215 class Simple extends SpecialMethodInvocation.AbstractBase {
216
217 /**
218 * The method description that is represented by this legal special method invocation.
219 */
220 private final MethodDescription methodDescription;
221
222 /**
223 * The type description that is represented by this legal special method invocation.
224 */
225 private final TypeDescription typeDescription;
226
227 /**
228 * A stack manipulation representing the method's invocation on the type description.
229 */
230 private final StackManipulation stackManipulation;
231
232 /**
233 * Creates a new legal special method invocation.
234 *
235 * @param methodDescription The method that represents the special method invocation.
236 * @param typeDescription The type on which the method should be invoked on by an {@code INVOKESPECIAL}
237 * invocation.
238 * @param stackManipulation The stack manipulation that represents this special method invocation.
239 */
240 protected Simple(MethodDescription methodDescription, TypeDescription typeDescription, StackManipulation stackManipulation) {
241 this.methodDescription = methodDescription;
242 this.typeDescription = typeDescription;
243 this.stackManipulation = stackManipulation;
244 }
245
246 /**
247 * Creates a special method invocation for a given invocation target.
248 *
249 * @param methodDescription The method that represents the special method invocation.
250 * @param typeDescription The type on which the method should be invoked on by an {@code INVOKESPECIAL}
251 * invocation.
252 * @return A special method invocation representing a legal invocation if the method can be invoked
253 * specially on the target type or an illegal invocation if this is not possible.
254 */
255 public static SpecialMethodInvocation of(MethodDescription methodDescription, TypeDescription typeDescription) {
256 StackManipulation stackManipulation = MethodInvocation.invoke(methodDescription).special(typeDescription);
257 return stackManipulation.isValid()
258 ? new Simple(methodDescription, typeDescription, stackManipulation)
259 : SpecialMethodInvocation.Illegal.INSTANCE;
260 }
261
262 /**
263 * {@inheritDoc}
264 */
265 public MethodDescription getMethodDescription() {
266 return methodDescription;
267 }
268
269 /**
270 * {@inheritDoc}
271 */
272 public TypeDescription getTypeDescription() {
273 return typeDescription;
274 }
275
276 /**
277 * {@inheritDoc}
278 */
279 public Size apply(MethodVisitor methodVisitor, Context implementationContext) {
280 return stackManipulation.apply(methodVisitor, implementationContext);
281 }
282
283 /**
284 * {@inheritDoc}
285 */
286 public SpecialMethodInvocation withCheckedCompatibilityTo(MethodDescription.TypeToken token) {
287 if (methodDescription.asTypeToken().equals(token)) {
288 return this;
289 } else {
290 return SpecialMethodInvocation.Illegal.INSTANCE;
291 }
292 }
293 }
294 }
295
296 /**
297 * The target of an implementation. Implementation targets must be immutable and can be queried without altering
298 * the implementation result. An implementation target provides information on the type that is to be created
299 * where it is the implementation's responsibility to cache expensive computations, especially such computations
300 * that require reflective look-up.
301 */
302 interface Target {
303
304 /**
305 * Returns a description of the instrumented type.
306 *
307 * @return A description of the instrumented type.
308 */
309 TypeDescription getInstrumentedType();
310
311 /**
312 * Identifies the origin type of an implementation. The origin type describes the type that is subject to
313 * any form of enhancement. If a subclass of a given type is generated, the base type of this subclass
314 * describes the origin type. If a given type is redefined or rebased, the origin type is described by the
315 * instrumented type itself.
316 *
317 * @return The origin type of this implementation.
318 */
319 TypeDefinition getOriginType();
320
321 /**
322 * Creates a special method invocation for invoking the super method of the given method.
323 *
324 * @param token A token of the method that is to be invoked as a super method.
325 * @return The corresponding special method invocation which might be illegal if the requested invocation is not legal.
326 */
327 SpecialMethodInvocation invokeSuper(MethodDescription.SignatureToken token);
328
329 /**
330 * Creates a special method invocation for invoking a default method with the given token. The default method call must
331 * not be ambiguous or an illegal special method invocation is returned.
332 *
333 * @param token A token of the method that is to be invoked as a default method.
334 * @return The corresponding default method invocation which might be illegal if the requested invocation is not legal or ambiguous.
335 */
336 SpecialMethodInvocation invokeDefault(MethodDescription.SignatureToken token);
337
338 /**
339 * Creates a special method invocation for invoking a default method.
340 *
341 * @param targetType The interface on which the default method is to be invoked.
342 * @param token A token that uniquely describes the method to invoke.
343 * @return The corresponding special method invocation which might be illegal if the requested invocation is
344 * not legal.
345 */
346 SpecialMethodInvocation invokeDefault(MethodDescription.SignatureToken token, TypeDescription targetType);
347
348 /**
349 * Invokes a dominant method, i.e. if the method token can be invoked as a super method invocation, this invocation is considered dominant.
350 * Alternatively, a method invocation is attempted on an interface type as a default method invocation only if this invocation is not ambiguous
351 * for several interfaces.
352 *
353 * @param token The method token representing the method to be invoked.
354 * @return A special method invocation for a method representing the method token.
355 */
356 SpecialMethodInvocation invokeDominant(MethodDescription.SignatureToken token);
357
358 /**
359 * A factory for creating an {@link Implementation.Target}.
360 */
361 interface Factory {
362
363 /**
364 * Creates an implementation target.
365 *
366 * @param instrumentedType The instrumented type.
367 * @param methodGraph A method graph of the instrumented type.
368 * @param classFileVersion The type's class file version.
369 * @return An implementation target for the instrumented type.
370 */
371 Target make(TypeDescription instrumentedType, MethodGraph.Linked methodGraph, ClassFileVersion classFileVersion);
372 }
373
374 /**
375 * An abstract base implementation for an {@link Implementation.Target}.
376 */
377 @HashCodeAndEqualsPlugin.Enhance
378 abstract class AbstractBase implements Target {
379
380 /**
381 * The instrumented type.
382 */
383 protected final TypeDescription instrumentedType;
384
385 /**
386 * The instrumented type's method graph.
387 */
388 protected final MethodGraph.Linked methodGraph;
389
390 /**
391 * The default method invocation mode to apply.
392 */
393 protected final DefaultMethodInvocation defaultMethodInvocation;
394
395 /**
396 * Creates a new implementation target.
397 *
398 * @param instrumentedType The instrumented type.
399 * @param methodGraph The instrumented type's method graph.
400 * @param defaultMethodInvocation The default method invocation mode to apply.
401 */
402 protected AbstractBase(TypeDescription instrumentedType, MethodGraph.Linked methodGraph, DefaultMethodInvocation defaultMethodInvocation) {
403 this.instrumentedType = instrumentedType;
404 this.methodGraph = methodGraph;
405 this.defaultMethodInvocation = defaultMethodInvocation;
406 }
407
408 /**
409 * {@inheritDoc}
410 */
411 public TypeDescription getInstrumentedType() {
412 return instrumentedType;
413 }
414
415 /**
416 * {@inheritDoc}
417 */
418 public SpecialMethodInvocation invokeDefault(MethodDescription.SignatureToken token) {
419 SpecialMethodInvocation specialMethodInvocation = SpecialMethodInvocation.Illegal.INSTANCE;
420 for (TypeDescription interfaceType : instrumentedType.getInterfaces().asErasures()) {
421 SpecialMethodInvocation invocation = invokeDefault(token, interfaceType).withCheckedCompatibilityTo(token.asTypeToken());
422 if (invocation.isValid()) {
423 if (specialMethodInvocation.isValid()) {
424 return SpecialMethodInvocation.Illegal.INSTANCE;
425 } else {
426 specialMethodInvocation = invocation;
427 }
428 }
429 }
430 return specialMethodInvocation;
431 }
432
433 /**
434 * {@inheritDoc}
435 */
436 public SpecialMethodInvocation invokeDefault(MethodDescription.SignatureToken token, TypeDescription targetType) {
437 return defaultMethodInvocation.apply(methodGraph.getInterfaceGraph(targetType).locate(token), targetType);
438 }
439
440 /**
441 * {@inheritDoc}
442 */
443 public SpecialMethodInvocation invokeDominant(MethodDescription.SignatureToken token) {
444 SpecialMethodInvocation specialMethodInvocation = invokeSuper(token);
445 return specialMethodInvocation.isValid()
446 ? specialMethodInvocation
447 : invokeDefault(token);
448 }
449
450 /**
451 * Determines if default method invocations are possible.
452 */
453 protected enum DefaultMethodInvocation {
454
455 /**
456 * Permits default method invocations, if an interface declaring a default method is possible.
457 */
458 ENABLED {
459 @Override
460 protected SpecialMethodInvocation apply(MethodGraph.Node node, TypeDescription targetType) {
461 return node.getSort().isUnique()
462 ? SpecialMethodInvocation.Simple.of(node.getRepresentative(), targetType)
463 : SpecialMethodInvocation.Illegal.INSTANCE;
464 }
465 },
466
467 /**
468 * Does not permit default method invocations.
469 */
470 DISABLED {
471 @Override
472 protected SpecialMethodInvocation apply(MethodGraph.Node node, TypeDescription targetType) {
473 return SpecialMethodInvocation.Illegal.INSTANCE;
474 }
475 };
476
477 /**
478 * Resolves a default method invocation depending on the class file version permitting such calls.
479 *
480 * @param classFileVersion The class file version to resolve for.
481 * @return A suitable default method invocation mode.
482 */
483 public static DefaultMethodInvocation of(ClassFileVersion classFileVersion) {
484 return classFileVersion.isAtLeast(ClassFileVersion.JAVA_V8)
485 ? ENABLED
486 : DISABLED;
487 }
488
489 /**
490 * Resolves a default method invocation for a given node.
491 *
492 * @param node The node representing the default method call.
493 * @param targetType The target type defining the default method.
494 * @return A suitable special method invocation.
495 */
496 protected abstract SpecialMethodInvocation apply(MethodGraph.Node node, TypeDescription targetType);
497 }
498 }
499 }
500
501 /**
502 * The context for an implementation application. An implementation context represents a mutable data structure
503 * where any registration is irrevocable. Calling methods on an implementation context should be considered equally
504 * sensitive as calling a {@link net.bytebuddy.jar.asm.MethodVisitor}. As such, an implementation context and a
505 * {@link net.bytebuddy.jar.asm.MethodVisitor} are complementary for creating an new Java type.
506 */
507 interface Context extends MethodAccessorFactory {
508
509 /**
510 * Registers an auxiliary type as required for the current implementation. Registering a type will cause the
511 * creation of this type even if this type is not effectively used for the current implementation.
512 *
513 * @param auxiliaryType The auxiliary type that is required for the current implementation.
514 * @return A description of the registered auxiliary type.
515 */
516 TypeDescription register(AuxiliaryType auxiliaryType);
517
518 /**
519 * Caches a single value by storing it in form of a {@code private}, {@code final} and {@code static} field.
520 * By caching values, expensive instance creations can be avoided and object identity can be preserved.
521 * The field is initiated in a generated class's static initializer.
522 *
523 * @param fieldValue A stack manipulation for creating the value that is to be cached in a {@code static} field.
524 * After executing the stack manipulation, exactly one value must be put onto the operand
525 * stack which is assignable to the given {@code fieldType}.
526 * @param fieldType The type of the field for storing the cached value. This field's type determines the value
527 * that is put onto the operand stack by this method's returned stack manipulation.
528 * @return A description of a field that was defined on the instrumented type which contains the given value.
529 */
530 FieldDescription.InDefinedShape cache(StackManipulation fieldValue, TypeDescription fieldType);
531
532 /**
533 * Returns the instrumented type of the current implementation. The instrumented type is exposed with the intend of allowing optimal
534 * byte code generation and not for implementing checks or changing the behavior of a {@link StackManipulation}.
535 *
536 * @return The instrumented type of the current implementation.
537 */
538 TypeDescription getInstrumentedType();
539
540 /**
541 * Returns the class file version of the currently created dynamic type.
542 *
543 * @return The class file version of the currently created dynamic type.
544 */
545 ClassFileVersion getClassFileVersion();
546
547 /**
548 * Represents an extractable view of an {@link Implementation.Context} which
549 * allows the retrieval of any registered auxiliary type.
550 */
551 interface ExtractableView extends Context {
552
553 /**
554 * Returns {@code true} if this implementation context permits the registration of any implicit type initializers.
555 *
556 * @return {@code true} if this implementation context permits the registration of any implicit type initializers.
557 */
558 boolean isEnabled();
559
560 /**
561 * Returns any {@link net.bytebuddy.implementation.auxiliary.AuxiliaryType} that was registered
562 * with this {@link Implementation.Context}.
563 *
564 * @return A list of all manifested registered auxiliary types.
565 */
566 List<DynamicType> getAuxiliaryTypes();
567
568 /**
569 * Writes any information that was registered with an {@link Implementation.Context}
570 * to the provided class visitor. This contains any fields for value caching, any accessor method and it
571 * writes the type initializer. The type initializer must therefore never be written manually.
572 *
573 * @param drain The drain to write the type initializer to.
574 * @param classVisitor The class visitor to which the extractable view is to be written.
575 * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotation.
576 */
577 void drain(TypeInitializer.Drain drain, ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
578
579 /**
580 * An abstract base implementation of an extractable view of an implementation context.
581 */
582 @HashCodeAndEqualsPlugin.Enhance
583 abstract class AbstractBase implements ExtractableView {
584
585 /**
586 * The instrumented type.
587 */
588 protected final TypeDescription instrumentedType;
589
590 /**
591 * The class file version of the dynamic type.
592 */
593 protected final ClassFileVersion classFileVersion;
594
595 /**
596 * Create a new extractable view.
597 *
598 * @param instrumentedType The instrumented type.
599 * @param classFileVersion The class file version of the dynamic type.
600 */
601 protected AbstractBase(TypeDescription instrumentedType, ClassFileVersion classFileVersion) {
602 this.instrumentedType = instrumentedType;
603 this.classFileVersion = classFileVersion;
604 }
605
606 /**
607 * {@inheritDoc}
608 */
609 public TypeDescription getInstrumentedType() {
610 return instrumentedType;
611 }
612
613 /**
614 * {@inheritDoc}
615 */
616 public ClassFileVersion getClassFileVersion() {
617 return classFileVersion;
618 }
619 }
620 }
621
622 /**
623 * A factory for creating a new implementation context.
624 */
625 interface Factory {
626
627 /**
628 * Creates a new implementation context.
629 *
630 * @param instrumentedType The description of the type that is currently subject of creation.
631 * @param auxiliaryTypeNamingStrategy The naming strategy for naming an auxiliary type.
632 * @param typeInitializer The type initializer of the created instrumented type.
633 * @param classFileVersion The class file version of the created class.
634 * @param auxiliaryClassFileVersion The class file version of any auxiliary classes.
635 * @return An implementation context in its extractable view.
636 */
637 ExtractableView make(TypeDescription instrumentedType,
638 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
639 TypeInitializer typeInitializer,
640 ClassFileVersion classFileVersion,
641 ClassFileVersion auxiliaryClassFileVersion);
642 }
643
644 /**
645 * An implementation context that does not allow for any injections into the static initializer block. This can be useful when
646 * redefining a class when it is not allowed to add methods to a class what is an implicit requirement when copying the static
647 * initializer block into another method.
648 */
649 class Disabled extends ExtractableView.AbstractBase {
650
651 /**
652 * Creates a new disabled implementation context.
653 *
654 * @param instrumentedType The instrumented type.
655 * @param classFileVersion The class file version to create the class in.
656 */
657 protected Disabled(TypeDescription instrumentedType, ClassFileVersion classFileVersion) {
658 super(instrumentedType, classFileVersion);
659 }
660
661 /**
662 * {@inheritDoc}
663 */
664 public boolean isEnabled() {
665 return false;
666 }
667
668 /**
669 * {@inheritDoc}
670 */
671 public List<DynamicType> getAuxiliaryTypes() {
672 return Collections.emptyList();
673 }
674
675 /**
676 * {@inheritDoc}
677 */
678 public void drain(TypeInitializer.Drain drain, ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
679 drain.apply(classVisitor, TypeInitializer.None.INSTANCE, this);
680 }
681
682 /**
683 * {@inheritDoc}
684 */
685 public TypeDescription register(AuxiliaryType auxiliaryType) {
686 throw new IllegalStateException("Registration of auxiliary types was disabled: " + auxiliaryType);
687 }
688
689 /**
690 * {@inheritDoc}
691 */
692 public MethodDescription.InDefinedShape registerAccessorFor(SpecialMethodInvocation specialMethodInvocation, AccessType accessType) {
693 throw new IllegalStateException("Registration of method accessors was disabled: " + specialMethodInvocation.getMethodDescription());
694 }
695
696 /**
697 * {@inheritDoc}
698 */
699 public MethodDescription.InDefinedShape registerGetterFor(FieldDescription fieldDescription, AccessType accessType) {
700 throw new IllegalStateException("Registration of field accessor was disabled: " + fieldDescription);
701 }
702
703 /**
704 * {@inheritDoc}
705 */
706 public MethodDescription.InDefinedShape registerSetterFor(FieldDescription fieldDescription, AccessType accessType) {
707 throw new IllegalStateException("Registration of field accessor was disabled: " + fieldDescription);
708 }
709
710 /**
711 * {@inheritDoc}
712 */
713 public FieldDescription.InDefinedShape cache(StackManipulation fieldValue, TypeDescription fieldType) {
714 throw new IllegalStateException("Field values caching was disabled: " + fieldType);
715 }
716
717 /**
718 * A factory for creating a {@link net.bytebuddy.implementation.Implementation.Context.Disabled}.
719 */
720 public enum Factory implements Context.Factory {
721
722 /**
723 * The singleton instance.
724 */
725 INSTANCE;
726
727 /**
728 * {@inheritDoc}
729 */
730 public ExtractableView make(TypeDescription instrumentedType,
731 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
732 TypeInitializer typeInitializer,
733 ClassFileVersion classFileVersion,
734 ClassFileVersion auxiliaryClassFileVersion) {
735 if (typeInitializer.isDefined()) {
736 throw new IllegalStateException("Cannot define type initializer which was explicitly disabled: " + typeInitializer);
737 }
738 return new Disabled(instrumentedType, classFileVersion);
739 }
740 }
741 }
742
743 /**
744 * A default implementation of an {@link Implementation.Context.ExtractableView}
745 * which serves as its own {@link MethodAccessorFactory}.
746 */
747 class Default extends ExtractableView.AbstractBase {
748
749 /**
750 * The name suffix to be appended to an accessor method.
751 */
752 public static final String ACCESSOR_METHOD_SUFFIX = "accessor";
753
754 /**
755 * The name prefix to be prepended to a field storing a cached value.
756 */
757 public static final String FIELD_CACHE_PREFIX = "cachedValue";
758
759 /**
760 * The naming strategy for naming auxiliary types that are registered.
761 */
762 private final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy;
763
764 /**
765 * The type initializer of the created instrumented type.
766 */
767 private final TypeInitializer typeInitializer;
768
769 /**
770 * The class file version to use for auxiliary classes.
771 */
772 private final ClassFileVersion auxiliaryClassFileVersion;
773
774 /**
775 * A mapping of special method invocations to their accessor methods that each invoke their mapped invocation.
776 */
777 private final Map<SpecialMethodInvocation, DelegationRecord> registeredAccessorMethods;
778
779 /**
780 * The registered getters.
781 */
782 private final Map<FieldDescription, DelegationRecord> registeredGetters;
783
784 /**
785 * The registered setters.
786 */
787 private final Map<FieldDescription, DelegationRecord> registeredSetters;
788
789 /**
790 * A map of registered auxiliary types to their dynamic type representation.
791 */
792 private final Map<AuxiliaryType, DynamicType> auxiliaryTypes;
793
794 /**
795 * A map of already registered field caches to their field representation.
796 */
797 private final Map<FieldCacheEntry, FieldDescription.InDefinedShape> registeredFieldCacheEntries;
798
799 /**
800 * A set of registered field cache entries.
801 */
802 private final Set<FieldDescription.InDefinedShape> registeredFieldCacheFields;
803
804 /**
805 * A random suffix to append to the names of accessor methods.
806 */
807 private final String suffix;
808
809 /**
810 * If {@code false}, the type initializer for this instance was already drained what prohibits the registration of additional cached field values.
811 */
812 private boolean fieldCacheCanAppendEntries;
813
814 /**
815 * Creates a new default implementation context.
816 *
817 * @param instrumentedType The description of the type that is currently subject of creation.
818 * @param classFileVersion The class file version of the created class.
819 * @param auxiliaryTypeNamingStrategy The naming strategy for naming an auxiliary type.
820 * @param typeInitializer The type initializer of the created instrumented type.
821 * @param auxiliaryClassFileVersion The class file version to use for auxiliary classes.
822 */
823 protected Default(TypeDescription instrumentedType,
824 ClassFileVersion classFileVersion,
825 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
826 TypeInitializer typeInitializer,
827 ClassFileVersion auxiliaryClassFileVersion) {
828 super(instrumentedType, classFileVersion);
829 this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy;
830 this.typeInitializer = typeInitializer;
831 this.auxiliaryClassFileVersion = auxiliaryClassFileVersion;
832 registeredAccessorMethods = new HashMap<SpecialMethodInvocation, DelegationRecord>();
833 registeredGetters = new HashMap<FieldDescription, DelegationRecord>();
834 registeredSetters = new HashMap<FieldDescription, DelegationRecord>();
835 auxiliaryTypes = new HashMap<AuxiliaryType, DynamicType>();
836 registeredFieldCacheEntries = new HashMap<FieldCacheEntry, FieldDescription.InDefinedShape>();
837 registeredFieldCacheFields = new HashSet<FieldDescription.InDefinedShape>();
838 suffix = RandomString.make();
839 fieldCacheCanAppendEntries = true;
840 }
841
842 /**
843 * {@inheritDoc}
844 */
845 public boolean isEnabled() {
846 return true;
847 }
848
849 /**
850 * {@inheritDoc}
851 */
852 public MethodDescription.InDefinedShape registerAccessorFor(SpecialMethodInvocation specialMethodInvocation, AccessType accessType) {
853 DelegationRecord record = registeredAccessorMethods.get(specialMethodInvocation);
854 record = record == null
855 ? new AccessorMethodDelegation(instrumentedType, suffix, accessType, specialMethodInvocation)
856 : record.with(accessType);
857 registeredAccessorMethods.put(specialMethodInvocation, record);
858 return record.getMethod();
859 }
860
861 /**
862 * {@inheritDoc}
863 */
864 public MethodDescription.InDefinedShape registerGetterFor(FieldDescription fieldDescription, AccessType accessType) {
865 DelegationRecord record = registeredGetters.get(fieldDescription);
866 record = record == null
867 ? new FieldGetterDelegation(instrumentedType, suffix, accessType, fieldDescription)
868 : record.with(accessType);
869 registeredGetters.put(fieldDescription, record);
870 return record.getMethod();
871 }
872
873 /**
874 * {@inheritDoc}
875 */
876 public MethodDescription.InDefinedShape registerSetterFor(FieldDescription fieldDescription, AccessType accessType) {
877 DelegationRecord record = registeredSetters.get(fieldDescription);
878 record = record == null
879 ? new FieldSetterDelegation(instrumentedType, suffix, accessType, fieldDescription)
880 : record.with(accessType);
881 registeredSetters.put(fieldDescription, record);
882 return record.getMethod();
883 }
884
885 /**
886 * {@inheritDoc}
887 */
888 public TypeDescription register(AuxiliaryType auxiliaryType) {
889 DynamicType dynamicType = auxiliaryTypes.get(auxiliaryType);
890 if (dynamicType == null) {
891 dynamicType = auxiliaryType.make(auxiliaryTypeNamingStrategy.name(instrumentedType), auxiliaryClassFileVersion, this);
892 auxiliaryTypes.put(auxiliaryType, dynamicType);
893 }
894 return dynamicType.getTypeDescription();
895 }
896
897 /**
898 * {@inheritDoc}
899 */
900 public List<DynamicType> getAuxiliaryTypes() {
901 return new ArrayList<DynamicType>(auxiliaryTypes.values());
902 }
903
904 /**
905 * {@inheritDoc}
906 */
907 public FieldDescription.InDefinedShape cache(StackManipulation fieldValue, TypeDescription fieldType) {
908 FieldCacheEntry fieldCacheEntry = new FieldCacheEntry(fieldValue, fieldType);
909 FieldDescription.InDefinedShape fieldCache = registeredFieldCacheEntries.get(fieldCacheEntry);
910 if (fieldCache != null) {
911 return fieldCache;
912 }
913 if (!fieldCacheCanAppendEntries) {
914 throw new IllegalStateException("Cached values cannot be registered after defining the type initializer for " + instrumentedType);
915 }
916 int hashCode = fieldValue.hashCode();
917 do {
918 fieldCache = new CacheValueField(instrumentedType, fieldType.asGenericType(), suffix, hashCode++);
919 } while (!registeredFieldCacheFields.add(fieldCache));
920 registeredFieldCacheEntries.put(fieldCacheEntry, fieldCache);
921 return fieldCache;
922 }
923
924 /**
925 * {@inheritDoc}
926 */
927 public void drain(TypeInitializer.Drain drain,
928 ClassVisitor classVisitor,
929 AnnotationValueFilter.Factory annotationValueFilterFactory) {
930 fieldCacheCanAppendEntries = false;
931 TypeInitializer typeInitializer = this.typeInitializer;
932 for (Map.Entry<FieldCacheEntry, FieldDescription.InDefinedShape> entry : registeredFieldCacheEntries.entrySet()) {
933 FieldVisitor fieldVisitor = classVisitor.visitField(entry.getValue().getModifiers(),
934 entry.getValue().getInternalName(),
935 entry.getValue().getDescriptor(),
936 entry.getValue().getGenericSignature(),
937 FieldDescription.NO_DEFAULT_VALUE);
938 if (fieldVisitor != null) {
939 fieldVisitor.visitEnd();
940 typeInitializer = typeInitializer.expandWith(entry.getKey().storeIn(entry.getValue()));
941 }
942 }
943 drain.apply(classVisitor, typeInitializer, this);
944 for (TypeWriter.MethodPool.Record record : registeredAccessorMethods.values()) {
945 record.apply(classVisitor, this, annotationValueFilterFactory);
946 }
947 for (TypeWriter.MethodPool.Record record : registeredGetters.values()) {
948 record.apply(classVisitor, this, annotationValueFilterFactory);
949 }
950 for (TypeWriter.MethodPool.Record record : registeredSetters.values()) {
951 record.apply(classVisitor, this, annotationValueFilterFactory);
952 }
953 }
954
955 /**
956 * A description of a field that stores a cached value.
957 */
958 protected static class CacheValueField extends FieldDescription.InDefinedShape.AbstractBase {
959
960 /**
961 * The instrumented type.
962 */
963 private final TypeDescription instrumentedType;
964
965 /**
966 * The type of the cache's field.
967 */
968 private final TypeDescription.Generic fieldType;
969
970 /**
971 * The name of the field.
972 */
973 private final String name;
974
975 /**
976 * Creates a new cache value field.
977 *
978 * @param instrumentedType The instrumented type.
979 * @param fieldType The type of the cache's field.
980 * @param suffix The suffix to use for the cache field's name.
981 * @param hashCode The hash value of the field's value for creating a unique field name.
982 */
983 protected CacheValueField(TypeDescription instrumentedType, TypeDescription.Generic fieldType, String suffix, int hashCode) {
984 this.instrumentedType = instrumentedType;
985 this.fieldType = fieldType;
986 name = FIELD_CACHE_PREFIX + "$" + suffix + "$" + RandomString.hashOf(hashCode);
987 }
988
989 /**
990 * {@inheritDoc}
991 */
992 public TypeDescription.Generic getType() {
993 return fieldType;
994 }
995
996 /**
997 * {@inheritDoc}
998 */
999 public AnnotationList getDeclaredAnnotations() {
1000 return new AnnotationList.Empty();
1001 }
1002
1003 /**
1004 * {@inheritDoc}
1005 */
1006 public TypeDescription getDeclaringType() {
1007 return instrumentedType;
1008 }
1009
1010 /**
1011 * {@inheritDoc}
1012 */
1013 public int getModifiers() {
1014 return Opcodes.ACC_SYNTHETIC | Opcodes.ACC_FINAL | Opcodes.ACC_STATIC | (instrumentedType.isInterface()
1015 ? Opcodes.ACC_PUBLIC
1016 : Opcodes.ACC_PRIVATE);
1017 }
1018
1019 /**
1020 * {@inheritDoc}
1021 */
1022 public String getName() {
1023 return name;
1024 }
1025 }
1026
1027 /**
1028 * A field cache entry for uniquely identifying a cached field. A cached field is described by the stack
1029 * manipulation that loads the field's value onto the operand stack and the type of the field.
1030 */
1031 protected static class FieldCacheEntry implements StackManipulation {
1032
1033 /**
1034 * The field value that is represented by this field cache entry.
1035 */
1036 private final StackManipulation fieldValue;
1037
1038 /**
1039 * The field type that is represented by this field cache entry.
1040 */
1041 private final TypeDescription fieldType;
1042
1043 /**
1044 * Creates a new field cache entry.
1045 *
1046 * @param fieldValue The field value that is represented by this field cache entry.
1047 * @param fieldType The field type that is represented by this field cache entry.
1048 */
1049 protected FieldCacheEntry(StackManipulation fieldValue, TypeDescription fieldType) {
1050 this.fieldValue = fieldValue;
1051 this.fieldType = fieldType;
1052 }
1053
1054 /**
1055 * Returns a stack manipulation where the represented value is stored in the given field.
1056 *
1057 * @param fieldDescription A static field in which the value is to be stored.
1058 * @return A byte code appender that represents this storage.
1059 */
1060 protected ByteCodeAppender storeIn(FieldDescription fieldDescription) {
1061 return new ByteCodeAppender.Simple(this, FieldAccess.forField(fieldDescription).write());
1062 }
1063
1064 /**
1065 * Returns the field type that is represented by this field cache entry.
1066 *
1067 * @return The field type that is represented by this field cache entry.
1068 */
1069 protected TypeDescription getFieldType() {
1070 return fieldType;
1071 }
1072
1073 /**
1074 * {@inheritDoc}
1075 */
1076 public boolean isValid() {
1077 return fieldValue.isValid();
1078 }
1079
1080 /**
1081 * {@inheritDoc}
1082 */
1083 public Size apply(MethodVisitor methodVisitor, Context implementationContext) {
1084 return fieldValue.apply(methodVisitor, implementationContext);
1085 }
1086
1087 @Override
1088 public int hashCode() {
1089 int result = fieldValue.hashCode();
1090 result = 31 * result + fieldType.hashCode();
1091 return result;
1092 }
1093
1094 @Override
1095 public boolean equals(Object other) {
1096 if (this == other) {
1097 return true;
1098 } else if (other == null || getClass() != other.getClass()) {
1099 return false;
1100 }
1101 FieldCacheEntry fieldCacheEntry = (FieldCacheEntry) other;
1102 return fieldValue.equals(fieldCacheEntry.fieldValue) && fieldType.equals(fieldCacheEntry.fieldType);
1103 }
1104 }
1105
1106 /**
1107 * A base implementation of a method that accesses a property of an instrumented type.
1108 */
1109 protected abstract static class AbstractPropertyAccessorMethod extends MethodDescription.InDefinedShape.AbstractBase {
1110
1111 /**
1112 * {@inheritDoc}
1113 */
1114 public int getModifiers() {
1115 return Opcodes.ACC_SYNTHETIC | getBaseModifiers() | (getDeclaringType().isInterface()
1116 ? Opcodes.ACC_PUBLIC
1117 : Opcodes.ACC_FINAL);
1118 }
1119
1120 /**
1121 * Returns the base modifiers, i.e. the modifiers that define the accessed property's features.
1122 *
1123 * @return Returns the base modifiers of the represented methods.
1124 */
1125 protected abstract int getBaseModifiers();
1126 }
1127
1128 /**
1129 * A description of an accessor method to access another method from outside the instrumented type.
1130 */
1131 protected static class AccessorMethod extends AbstractPropertyAccessorMethod {
1132
1133 /**
1134 * The instrumented type.
1135 */
1136 private final TypeDescription instrumentedType;
1137
1138 /**
1139 * The method that is being accessed.
1140 */
1141 private final MethodDescription methodDescription;
1142
1143 /**
1144 * The name of the method.
1145 */
1146 private final String name;
1147
1148 /**
1149 * Creates a new accessor method.
1150 *
1151 * @param instrumentedType The instrumented type.
1152 * @param methodDescription The method that is being accessed.
1153 * @param suffix The suffix to append to the accessor method's name.
1154 */
1155 protected AccessorMethod(TypeDescription instrumentedType, MethodDescription methodDescription, String suffix) {
1156 this.instrumentedType = instrumentedType;
1157 this.methodDescription = methodDescription;
1158 name = methodDescription.getInternalName() + "$" + ACCESSOR_METHOD_SUFFIX + "$" + suffix;
1159 }
1160
1161 /**
1162 * {@inheritDoc}
1163 */
1164 public TypeDescription.Generic getReturnType() {
1165 return methodDescription.getReturnType().asRawType();
1166 }
1167
1168 /**
1169 * {@inheritDoc}
1170 */
1171 public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1172 return new ParameterList.Explicit.ForTypes(this, methodDescription.getParameters().asTypeList().asRawTypes());
1173 }
1174
1175 /**
1176 * {@inheritDoc}
1177 */
1178 public TypeList.Generic getExceptionTypes() {
1179 return methodDescription.getExceptionTypes().asRawTypes();
1180 }
1181
1182 /**
1183 * {@inheritDoc}
1184 */
1185 public AnnotationValue<?, ?> getDefaultValue() {
1186 return AnnotationValue.UNDEFINED;
1187 }
1188
1189 /**
1190 * {@inheritDoc}
1191 */
1192 public TypeList.Generic getTypeVariables() {
1193 return new TypeList.Generic.Empty();
1194 }
1195
1196 /**
1197 * {@inheritDoc}
1198 */
1199 public AnnotationList getDeclaredAnnotations() {
1200 return new AnnotationList.Empty();
1201 }
1202
1203 /**
1204 * {@inheritDoc}
1205 */
1206 public TypeDescription getDeclaringType() {
1207 return instrumentedType;
1208 }
1209
1210 @Override
1211 protected int getBaseModifiers() {
1212 return methodDescription.isStatic()
1213 ? Opcodes.ACC_STATIC
1214 : EMPTY_MASK;
1215 }
1216
1217 /**
1218 * {@inheritDoc}
1219 */
1220 public String getInternalName() {
1221 return name;
1222 }
1223 }
1224
1225 /**
1226 * A description of a field getter method.
1227 */
1228 protected static class FieldGetter extends AbstractPropertyAccessorMethod {
1229
1230 /**
1231 * The instrumented type.
1232 */
1233 private final TypeDescription instrumentedType;
1234
1235 /**
1236 * The field for which a getter is described.
1237 */
1238 private final FieldDescription fieldDescription;
1239
1240 /**
1241 * The name of the getter method.
1242 */
1243 private final String name;
1244
1245 /**
1246 * Creates a new field getter.
1247 *
1248 * @param instrumentedType The instrumented type.
1249 * @param fieldDescription The field for which a getter is described.
1250 * @param suffix The name suffix for the field getter method.
1251 */
1252 protected FieldGetter(TypeDescription instrumentedType, FieldDescription fieldDescription, String suffix) {
1253 this.instrumentedType = instrumentedType;
1254 this.fieldDescription = fieldDescription;
1255 name = fieldDescription.getName() + "$" + ACCESSOR_METHOD_SUFFIX + "$" + suffix;
1256 }
1257
1258 /**
1259 * {@inheritDoc}
1260 */
1261 public TypeDescription.Generic getReturnType() {
1262 return fieldDescription.getType().asRawType();
1263 }
1264
1265 /**
1266 * {@inheritDoc}
1267 */
1268 public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1269 return new ParameterList.Empty<ParameterDescription.InDefinedShape>();
1270 }
1271
1272 /**
1273 * {@inheritDoc}
1274 */
1275 public TypeList.Generic getExceptionTypes() {
1276 return new TypeList.Generic.Empty();
1277 }
1278
1279 /**
1280 * {@inheritDoc}
1281 */
1282 public AnnotationValue<?, ?> getDefaultValue() {
1283 return AnnotationValue.UNDEFINED;
1284 }
1285
1286 /**
1287 * {@inheritDoc}
1288 */
1289 public TypeList.Generic getTypeVariables() {
1290 return new TypeList.Generic.Empty();
1291 }
1292
1293 /**
1294 * {@inheritDoc}
1295 */
1296 public AnnotationList getDeclaredAnnotations() {
1297 return new AnnotationList.Empty();
1298 }
1299
1300 /**
1301 * {@inheritDoc}
1302 */
1303 public TypeDescription getDeclaringType() {
1304 return instrumentedType;
1305 }
1306
1307 @Override
1308 protected int getBaseModifiers() {
1309 return fieldDescription.isStatic()
1310 ? Opcodes.ACC_STATIC
1311 : EMPTY_MASK;
1312 }
1313
1314 /**
1315 * {@inheritDoc}
1316 */
1317 public String getInternalName() {
1318 return name;
1319 }
1320 }
1321
1322 /**
1323 * A description of a field setter method.
1324 */
1325 protected static class FieldSetter extends AbstractPropertyAccessorMethod {
1326
1327 /**
1328 * The instrumented type.
1329 */
1330 private final TypeDescription instrumentedType;
1331
1332 /**
1333 * The field for which a setter is described.
1334 */
1335 private final FieldDescription fieldDescription;
1336
1337 /**
1338 * The name of the field setter.
1339 */
1340 private final String name;
1341
1342 /**
1343 * Creates a new field setter.
1344 *
1345 * @param instrumentedType The instrumented type.
1346 * @param fieldDescription The field for which a setter is described.
1347 * @param suffix The name suffix for the field setter method.
1348 */
1349 protected FieldSetter(TypeDescription instrumentedType, FieldDescription fieldDescription, String suffix) {
1350 this.instrumentedType = instrumentedType;
1351 this.fieldDescription = fieldDescription;
1352 name = fieldDescription.getName() + "$" + ACCESSOR_METHOD_SUFFIX + "$" + suffix;
1353 }
1354
1355 /**
1356 * {@inheritDoc}
1357 */
1358 public TypeDescription.Generic getReturnType() {
1359 return TypeDescription.Generic.VOID;
1360 }
1361
1362 /**
1363 * {@inheritDoc}
1364 */
1365 public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1366 return new ParameterList.Explicit.ForTypes(this, Collections.singletonList(fieldDescription.getType().asRawType()));
1367 }
1368
1369 /**
1370 * {@inheritDoc}
1371 */
1372 public TypeList.Generic getExceptionTypes() {
1373 return new TypeList.Generic.Empty();
1374 }
1375
1376 /**
1377 * {@inheritDoc}
1378 */
1379 public AnnotationValue<?, ?> getDefaultValue() {
1380 return AnnotationValue.UNDEFINED;
1381 }
1382
1383 /**
1384 * {@inheritDoc}
1385 */
1386 public TypeList.Generic getTypeVariables() {
1387 return new TypeList.Generic.Empty();
1388 }
1389
1390 /**
1391 * {@inheritDoc}
1392 */
1393 public AnnotationList getDeclaredAnnotations() {
1394 return new AnnotationList.Empty();
1395 }
1396
1397 /**
1398 * {@inheritDoc}
1399 */
1400 public TypeDescription getDeclaringType() {
1401 return instrumentedType;
1402 }
1403
1404 @Override
1405 protected int getBaseModifiers() {
1406 return fieldDescription.isStatic()
1407 ? Opcodes.ACC_STATIC
1408 : EMPTY_MASK;
1409 }
1410
1411 /**
1412 * {@inheritDoc}
1413 */
1414 public String getInternalName() {
1415 return name;
1416 }
1417 }
1418
1419 /**
1420 * An abstract method pool entry that delegates the implementation of a method to itself.
1421 */
1422 @HashCodeAndEqualsPlugin.Enhance
1423 protected abstract static class DelegationRecord extends TypeWriter.MethodPool.Record.ForDefinedMethod implements ByteCodeAppender {
1424
1425 /**
1426 * The delegation method.
1427 */
1428 protected final MethodDescription.InDefinedShape methodDescription;
1429
1430 /**
1431 * The record's visibility.
1432 */
1433 protected final Visibility visibility;
1434
1435 /**
1436 * Creates a new delegation record.
1437 *
1438 * @param methodDescription The delegation method.
1439 * @param visibility The method's actual visibility.
1440 */
1441 protected DelegationRecord(MethodDescription.InDefinedShape methodDescription, Visibility visibility) {
1442 this.methodDescription = methodDescription;
1443 this.visibility = visibility;
1444 }
1445
1446 /**
1447 * Returns this delegation record with the minimal visibility represented by the supplied access type.
1448 *
1449 * @param accessType The access type to enforce.
1450 * @return A new version of this delegation record with the minimal implied visibility.
1451 */
1452 protected abstract DelegationRecord with(AccessType accessType);
1453
1454 /**
1455 * {@inheritDoc}
1456 */
1457 public MethodDescription.InDefinedShape getMethod() {
1458 return methodDescription;
1459 }
1460
1461 /**
1462 * {@inheritDoc}
1463 */
1464 public Sort getSort() {
1465 return Sort.IMPLEMENTED;
1466 }
1467
1468 /**
1469 * {@inheritDoc}
1470 */
1471 public Visibility getVisibility() {
1472 return visibility;
1473 }
1474
1475 /**
1476 * {@inheritDoc}
1477 */
1478 public void applyHead(MethodVisitor methodVisitor) {
1479 /* do nothing */
1480 }
1481
1482 /**
1483 * {@inheritDoc}
1484 */
1485 public void applyBody(MethodVisitor methodVisitor, Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1486 methodVisitor.visitCode();
1487 Size size = applyCode(methodVisitor, implementationContext);
1488 methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1489 }
1490
1491 /**
1492 * {@inheritDoc}
1493 */
1494 public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1495 /* do nothing */
1496 }
1497
1498 /**
1499 * {@inheritDoc}
1500 */
1501 public Size applyCode(MethodVisitor methodVisitor, Context implementationContext) {
1502 return apply(methodVisitor, implementationContext, getMethod());
1503 }
1504
1505 /**
1506 * {@inheritDoc}
1507 */
1508 public TypeWriter.MethodPool.Record prepend(ByteCodeAppender byteCodeAppender) {
1509 throw new UnsupportedOperationException("Cannot prepend code to a delegation for " + methodDescription);
1510 }
1511 }
1512
1513 /**
1514 * An implementation of a {@link TypeWriter.MethodPool.Record} for implementing
1515 * an accessor method.
1516 */
1517 @HashCodeAndEqualsPlugin.Enhance
1518 protected static class AccessorMethodDelegation extends DelegationRecord {
1519
1520 /**
1521 * The stack manipulation that represents the requested special method invocation.
1522 */
1523 private final StackManipulation accessorMethodInvocation;
1524
1525 /**
1526 * Creates a delegation to an accessor method.
1527 *
1528 * @param instrumentedType The instrumented type.
1529 * @param suffix The suffix to append to the method.
1530 * @param accessType The access type.
1531 * @param specialMethodInvocation The actual method's invocation.
1532 */
1533 protected AccessorMethodDelegation(TypeDescription instrumentedType,
1534 String suffix,
1535 AccessType accessType,
1536 SpecialMethodInvocation specialMethodInvocation) {
1537 this(new AccessorMethod(instrumentedType, specialMethodInvocation.getMethodDescription(), suffix),
1538 accessType.getVisibility(),
1539 specialMethodInvocation);
1540 }
1541
1542 /**
1543 * Creates a delegation to an accessor method.
1544 *
1545 * @param methodDescription The accessor method.
1546 * @param visibility The method's visibility.
1547 * @param accessorMethodInvocation The actual method's invocation.
1548 */
1549 private AccessorMethodDelegation(MethodDescription.InDefinedShape methodDescription,
1550 Visibility visibility,
1551 StackManipulation accessorMethodInvocation) {
1552 super(methodDescription, visibility);
1553 this.accessorMethodInvocation = accessorMethodInvocation;
1554 }
1555
1556 @Override
1557 protected DelegationRecord with(AccessType accessType) {
1558 return new AccessorMethodDelegation(methodDescription, visibility.expandTo(accessType.getVisibility()), accessorMethodInvocation);
1559 }
1560
1561 /**
1562 * {@inheritDoc}
1563 */
1564 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
1565 StackManipulation.Size stackSize = new StackManipulation.Compound(
1566 MethodVariableAccess.allArgumentsOf(instrumentedMethod).prependThisReference(),
1567 accessorMethodInvocation,
1568 MethodReturn.of(instrumentedMethod.getReturnType())
1569 ).apply(methodVisitor, implementationContext);
1570 return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize());
1571 }
1572 }
1573
1574 /**
1575 * An implementation for a field getter.
1576 */
1577 @HashCodeAndEqualsPlugin.Enhance
1578 protected static class FieldGetterDelegation extends DelegationRecord {
1579
1580 /**
1581 * The field to read from.
1582 */
1583 private final FieldDescription fieldDescription;
1584
1585 /**
1586 * Creates a new field getter implementation.
1587 *
1588 * @param instrumentedType The instrumented type.
1589 * @param suffix The suffix to use for the setter method.
1590 * @param accessType The method's access type.
1591 * @param fieldDescription The field to write to.
1592 */
1593 protected FieldGetterDelegation(TypeDescription instrumentedType, String suffix, AccessType accessType, FieldDescription fieldDescription) {
1594 this(new FieldGetter(instrumentedType, fieldDescription, suffix), accessType.getVisibility(), fieldDescription);
1595 }
1596
1597 /**
1598 * Creates a new field getter implementation.
1599 *
1600 * @param methodDescription The delegation method.
1601 * @param visibility The delegation method's visibility.
1602 * @param fieldDescription The field to read.
1603 */
1604 private FieldGetterDelegation(MethodDescription.InDefinedShape methodDescription, Visibility visibility, FieldDescription fieldDescription) {
1605 super(methodDescription, visibility);
1606 this.fieldDescription = fieldDescription;
1607 }
1608
1609 @Override
1610 protected DelegationRecord with(AccessType accessType) {
1611 return new FieldGetterDelegation(methodDescription, visibility.expandTo(accessType.getVisibility()), fieldDescription);
1612 }
1613
1614 /**
1615 * {@inheritDoc}
1616 */
1617 public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
1618 StackManipulation.Size stackSize = new StackManipulation.Compound(
1619 fieldDescription.isStatic()
1620 ? StackManipulation.Trivial.INSTANCE
1621 : MethodVariableAccess.loadThis(),
1622 FieldAccess.forField(fieldDescription).read(),
1623 MethodReturn.of(fieldDescription.getType())
1624 ).apply(methodVisitor, implementationContext);
1625 return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize());
1626 }
1627 }
1628
1629 /**
1630 * An implementation for a field setter.
1631 */
1632 @HashCodeAndEqualsPlugin.Enhance
1633 protected static class FieldSetterDelegation extends DelegationRecord {
1634
1635 /**
1636 * The field to write to.
1637 */
1638 private final FieldDescription fieldDescription;
1639
1640 /**
1641 * Creates a new field setter implementation.
1642 *
1643 * @param instrumentedType The instrumented type.
1644 * @param suffix The suffix to use for the setter method.
1645 * @param accessType The method's access type.
1646 * @param fieldDescription The field to write to.
1647 */
1648 protected FieldSetterDelegation(TypeDescription instrumentedType, String suffix, AccessType accessType, FieldDescription fieldDescription) {
1649 this(new FieldSetter(instrumentedType, fieldDescription, suffix), accessType.getVisibility(), fieldDescription);
1650 }
1651
1652 /**
1653 * Creates a new field setter.
1654 *
1655 * @param methodDescription The field accessor method.
1656 * @param visibility The delegation method's visibility.
1657 * @param fieldDescription The field to write to.
1658 */
1659 private FieldSetterDelegation(MethodDescription.InDefinedShape methodDescription, Visibility visibility, FieldDescription fieldDescription) {
1660 super(methodDescription, visibility);
1661 this.fieldDescription = fieldDescription;
1662 }
1663
1664 @Override
1665 protected DelegationRecord with(AccessType accessType) {
1666 return new FieldSetterDelegation(methodDescription, visibility.expandTo(accessType.getVisibility()), fieldDescription);
1667 }
1668
1669 /**
1670 * {@inheritDoc}
1671 */
1672 public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
1673 StackManipulation.Size stackSize = new StackManipulation.Compound(
1674 MethodVariableAccess.allArgumentsOf(instrumentedMethod).prependThisReference(),
1675 FieldAccess.forField(fieldDescription).write(),
1676 MethodReturn.VOID
1677 ).apply(methodVisitor, implementationContext);
1678 return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize());
1679 }
1680 }
1681
1682 /**
1683 * A factory for creating a {@link net.bytebuddy.implementation.Implementation.Context.Default}.
1684 */
1685 public enum Factory implements ExtractableView.Factory {
1686
1687 /**
1688 * The singleton instance.
1689 */
1690 INSTANCE;
1691
1692 /**
1693 * {@inheritDoc}
1694 */
1695 public ExtractableView make(TypeDescription instrumentedType,
1696 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
1697 TypeInitializer typeInitializer,
1698 ClassFileVersion classFileVersion,
1699 ClassFileVersion auxiliaryClassFileVersion) {
1700 return new Default(instrumentedType, classFileVersion, auxiliaryTypeNamingStrategy, typeInitializer, auxiliaryClassFileVersion);
1701 }
1702 }
1703 }
1704 }
1705
1706 /**
1707 * A compound implementation that allows to combine several implementations.
1708 * <p> </p>
1709 * Note that the combination of two implementation might break the contract for implementing
1710 * {@link java.lang.Object#equals(Object)} and {@link Object#hashCode()} as described for
1711 * {@link Implementation}.
1712 *
1713 * @see Implementation
1714 */
1715 @HashCodeAndEqualsPlugin.Enhance
1716 class Compound implements Implementation {
1717
1718 /**
1719 * All implementation that are represented by this compound implementation.
1720 */
1721 private final List<Implementation> implementations;
1722
1723 /**
1724 * Creates a new immutable compound implementation.
1725 *
1726 * @param implementation The implementations to combine in their order.
1727 */
1728 public Compound(Implementation... implementation) {
1729 this(Arrays.asList(implementation));
1730 }
1731
1732 /**
1733 * Creates a new immutable compound implementation.
1734 *
1735 * @param implementations The implementations to combine in their order.
1736 */
1737 public Compound(List<? extends Implementation> implementations) {
1738 this.implementations = new ArrayList<Implementation>();
1739 for (Implementation implementation : implementations) {
1740 if (implementation instanceof Compound.Composable) {
1741 this.implementations.addAll(((Compound.Composable) implementation).implementations);
1742 this.implementations.add(((Compound.Composable) implementation).composable);
1743 } else if (implementation instanceof Compound) {
1744 this.implementations.addAll(((Compound) implementation).implementations);
1745 } else {
1746 this.implementations.add(implementation);
1747 }
1748 }
1749 }
1750
1751 /**
1752 * {@inheritDoc}
1753 */
1754 public InstrumentedType prepare(InstrumentedType instrumentedType) {
1755 for (Implementation implementation : implementations) {
1756 instrumentedType = implementation.prepare(instrumentedType);
1757 }
1758 return instrumentedType;
1759 }
1760
1761 /**
1762 * {@inheritDoc}
1763 */
1764 public ByteCodeAppender appender(Target implementationTarget) {
1765 ByteCodeAppender[] byteCodeAppender = new ByteCodeAppender[implementations.size()];
1766 int index = 0;
1767 for (Implementation implementation : implementations) {
1768 byteCodeAppender[index++] = implementation.appender(implementationTarget);
1769 }
1770 return new ByteCodeAppender.Compound(byteCodeAppender);
1771 }
1772
1773 /**
1774 * A compound implementation that allows to combine several implementations and that is {@link Implementation.Composable}.
1775 * <p> </p>
1776 * Note that the combination of two implementation might break the contract for implementing
1777 * {@link java.lang.Object#equals(Object)} and {@link Object#hashCode()} as described for
1778 * {@link Implementation}.
1779 *
1780 * @see Implementation
1781 */
1782 @HashCodeAndEqualsPlugin.Enhance
1783 public static class Composable implements Implementation.Composable {
1784
1785 /**
1786 * The composable implementation that is applied last.
1787 */
1788 private final Implementation.Composable composable;
1789
1790 /**
1791 * All implementation that are represented by this compound implementation.
1792 */
1793 private final List<Implementation> implementations;
1794
1795 /**
1796 * Creates a new compound composable.
1797 *
1798 * @param implementation An implementation that is represented by this compound implementation prior to the composable.
1799 * @param composable The composable implementation that is applied last.
1800 */
1801 public Composable(Implementation implementation, Implementation.Composable composable) {
1802 this(Collections.singletonList(implementation), composable);
1803 }
1804
1805 /**
1806 * Creates a new compound composable.
1807 *
1808 * @param implementations All implementation that are represented by this compound implementation excluding the composable.
1809 * @param composable The composable implementation that is applied last.
1810 */
1811 public Composable(List<? extends Implementation> implementations, Implementation.Composable composable) {
1812 this.implementations = new ArrayList<Implementation>();
1813 for (Implementation implementation : implementations) {
1814 if (implementation instanceof Compound.Composable) {
1815 this.implementations.addAll(((Compound.Composable) implementation).implementations);
1816 this.implementations.add(((Compound.Composable) implementation).composable);
1817 } else if (implementation instanceof Compound) {
1818 this.implementations.addAll(((Compound) implementation).implementations);
1819 } else {
1820 this.implementations.add(implementation);
1821 }
1822 }
1823 if (composable instanceof Compound.Composable) {
1824 this.implementations.addAll(((Compound.Composable) composable).implementations);
1825 this.composable = ((Compound.Composable) composable).composable;
1826 } else {
1827 this.composable = composable;
1828 }
1829 }
1830
1831 /**
1832 * {@inheritDoc}
1833 */
1834 public InstrumentedType prepare(InstrumentedType instrumentedType) {
1835 for (Implementation implementation : implementations) {
1836 instrumentedType = implementation.prepare(instrumentedType);
1837 }
1838 return composable.prepare(instrumentedType);
1839 }
1840
1841 /**
1842 * {@inheritDoc}
1843 */
1844 public ByteCodeAppender appender(Target implementationTarget) {
1845 ByteCodeAppender[] byteCodeAppender = new ByteCodeAppender[implementations.size() + 1];
1846 int index = 0;
1847 for (Implementation implementation : implementations) {
1848 byteCodeAppender[index++] = implementation.appender(implementationTarget);
1849 }
1850 byteCodeAppender[index] = composable.appender(implementationTarget);
1851 return new ByteCodeAppender.Compound(byteCodeAppender);
1852 }
1853
1854 /**
1855 * {@inheritDoc}
1856 */
1857 public Implementation andThen(Implementation implementation) {
1858 return new Compound(CompoundList.of(implementations, composable.andThen(implementation)));
1859 }
1860
1861 /**
1862 * {@inheritDoc}
1863 */
1864 public Implementation.Composable andThen(Implementation.Composable implementation) {
1865 return new Compound.Composable(implementations, composable.andThen(implementation));
1866 }
1867 }
1868 }
1869
1870 /**
1871 * A simple implementation that does not register any members with the instrumented type.
1872 */
1873 @HashCodeAndEqualsPlugin.Enhance
1874 class Simple implements Implementation {
1875
1876 /**
1877 * The byte code appender to emmit.
1878 */
1879 private final ByteCodeAppender byteCodeAppender;
1880
1881 /**
1882 * Creates a new simple implementation for the given byte code appenders.
1883 *
1884 * @param byteCodeAppender The byte code appenders to apply in their order of application.
1885 */
1886 public Simple(ByteCodeAppender... byteCodeAppender) {
1887 this.byteCodeAppender = new ByteCodeAppender.Compound(byteCodeAppender);
1888 }
1889
1890 /**
1891 * Creates a new simple instrumentation for the given stack manipulations which are summarized in a
1892 * byte code appender that defines any requested method by these manipulations.
1893 *
1894 * @param stackManipulation The stack manipulation to apply in their order of application.
1895 */
1896 public Simple(StackManipulation... stackManipulation) {
1897 byteCodeAppender = new ByteCodeAppender.Simple(stackManipulation);
1898 }
1899
1900 /**
1901 * {@inheritDoc}
1902 */
1903 public InstrumentedType prepare(InstrumentedType instrumentedType) {
1904 return instrumentedType;
1905 }
1906
1907 /**
1908 * {@inheritDoc}
1909 */
1910 public ByteCodeAppender appender(Target implementationTarget) {
1911 return byteCodeAppender;
1912 }
1913 }
1914 }
1915