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.bind.annotation;
17
18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
20 import net.bytebuddy.description.annotation.AnnotationDescription;
21 import net.bytebuddy.description.field.FieldDescription;
22 import net.bytebuddy.description.method.MethodDescription;
23 import net.bytebuddy.description.method.ParameterDescription;
24 import net.bytebuddy.description.type.TypeDescription;
25 import net.bytebuddy.dynamic.scaffold.FieldLocator;
26 import net.bytebuddy.implementation.Implementation;
27 import net.bytebuddy.implementation.bind.MethodDelegationBinder;
28 import net.bytebuddy.implementation.bytecode.StackManipulation;
29 import net.bytebuddy.implementation.bytecode.assign.Assigner;
30 import net.bytebuddy.implementation.bytecode.constant.*;
31 import net.bytebuddy.utility.JavaConstant;
32 import net.bytebuddy.utility.JavaType;
33
34 import java.lang.annotation.Annotation;
35 import java.util.*;
36
37 import static net.bytebuddy.matcher.ElementMatchers.isGetter;
38 import static net.bytebuddy.matcher.ElementMatchers.isSetter;
39
40 /**
41  * This {@link net.bytebuddy.implementation.bind.MethodDelegationBinder} binds
42  * method by analyzing annotations found on the <i>target</i> method that is subject to a method binding.
43  */

44 @HashCodeAndEqualsPlugin.Enhance
45 public class TargetMethodAnnotationDrivenBinder implements MethodDelegationBinder {
46
47     /**
48      * The processor for performing an actual method delegation.
49      */

50     private final DelegationProcessor delegationProcessor;
51
52     /**
53      * Creates a new target method annotation-driven binder.
54      *
55      * @param delegationProcessor The delegation processor to use.
56      */

57     protected TargetMethodAnnotationDrivenBinder(DelegationProcessor delegationProcessor) {
58         this.delegationProcessor = delegationProcessor;
59     }
60
61     /**
62      * Creates a new method delegation binder that binds method based on annotations found on the target method.
63      *
64      * @param parameterBinders A list of parameter binder delegates. Each such delegate is responsible for creating a
65      *                         {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.ParameterBinding}
66      *                         for a specific annotation.
67      * @return An appropriate method delegation binder.
68      */

69     public static MethodDelegationBinder of(List<? extends ParameterBinder<?>> parameterBinders) {
70         return new TargetMethodAnnotationDrivenBinder(DelegationProcessor.of(parameterBinders));
71     }
72
73     /**
74      * {@inheritDoc}
75      */

76     public MethodDelegationBinder.Record compile(MethodDescription candidate) {
77         if (IgnoreForBinding.Verifier.check(candidate)) {
78             return MethodDelegationBinder.Record.Illegal.INSTANCE;
79         }
80         List<DelegationProcessor.Handler> handlers = new ArrayList<DelegationProcessor.Handler>(candidate.getParameters().size());
81         for (ParameterDescription parameterDescription : candidate.getParameters()) {
82             handlers.add(delegationProcessor.prepare(parameterDescription));
83         }
84         return new Record(candidate, handlers, RuntimeType.Verifier.check(candidate));
85     }
86
87     /**
88      * A compiled record of a target method annotation-driven binder.
89      */

90     @HashCodeAndEqualsPlugin.Enhance
91     protected static class Record implements MethodDelegationBinder.Record {
92
93         /**
94          * The candidate method.
95          */

96         private final MethodDescription candidate;
97
98         /**
99          * A list of handlers for each parameter.
100          */

101         private final List<DelegationProcessor.Handler> handlers;
102
103         /**
104          * The typing to apply.
105          */

106         private final Assigner.Typing typing;
107
108         /**
109          * Creates a default compiled method delegation binder.
110          *
111          * @param candidate The candidate method.
112          * @param handlers  A list of handlers for each parameter.
113          * @param typing    The typing to apply.
114          */

115         protected Record(MethodDescription candidate, List<DelegationProcessor.Handler> handlers, Assigner.Typing typing) {
116             this.candidate = candidate;
117             this.handlers = handlers;
118             this.typing = typing;
119         }
120
121         /**
122          * {@inheritDoc}
123          */

124         public MethodBinding bind(Implementation.Target implementationTarget,
125                                   MethodDescription source,
126                                   MethodDelegationBinder.TerminationHandler terminationHandler,
127                                   MethodInvoker methodInvoker,
128                                   Assigner assigner) {
129             if (!candidate.isAccessibleTo(implementationTarget.getInstrumentedType())) {
130                 return MethodBinding.Illegal.INSTANCE;
131             }
132             StackManipulation methodTermination = terminationHandler.resolve(assigner, typing, source, candidate);
133             if (!methodTermination.isValid()) {
134                 return MethodBinding.Illegal.INSTANCE;
135             }
136             MethodBinding.Builder methodDelegationBindingBuilder = new MethodBinding.Builder(methodInvoker, candidate);
137             for (DelegationProcessor.Handler handler : handlers) {
138                 ParameterBinding<?> parameterBinding = handler.bind(source, implementationTarget, assigner);
139                 if (!parameterBinding.isValid() || !methodDelegationBindingBuilder.append(parameterBinding)) {
140                     return MethodBinding.Illegal.INSTANCE;
141                 }
142             }
143             return methodDelegationBindingBuilder.build(methodTermination);
144         }
145
146         @Override
147         public String toString() {
148             return candidate.toString();
149         }
150     }
151
152     /**
153      * A parameter binder is used as a delegate for binding a parameter according to a particular annotation type found
154      * on this parameter.
155      *
156      * @param <T> The {@link java.lang.annotation.Annotation#annotationType()} handled by this parameter binder.
157      */

158     @SuppressFBWarnings(value = "IC_SUPERCLASS_USES_SUBCLASS_DURING_INITIALIZATION", justification = "Safe initialization is implied")
159     public interface ParameterBinder<T extends Annotation> {
160
161         /**
162          * The default parameter binders to be used.
163          */

164         List<ParameterBinder<?>> DEFAULTS = Collections.unmodifiableList(Arrays.<TargetMethodAnnotationDrivenBinder.ParameterBinder<?>>asList(
165                 Argument.Binder.INSTANCE,
166                 AllArguments.Binder.INSTANCE,
167                 Origin.Binder.INSTANCE,
168                 This.Binder.INSTANCE,
169                 Super.Binder.INSTANCE,
170                 Default.Binder.INSTANCE,
171                 SuperCall.Binder.INSTANCE,
172                 DefaultCall.Binder.INSTANCE,
173                 SuperMethod.Binder.INSTANCE,
174                 DefaultMethod.Binder.INSTANCE,
175                 FieldValue.Binder.INSTANCE,
176                 StubValue.Binder.INSTANCE,
177                 Empty.Binder.INSTANCE));
178
179         /**
180          * The annotation type that is handled by this parameter binder.
181          *
182          * @return The {@link java.lang.annotation.Annotation#annotationType()} handled by this parameter binder.
183          */

184         Class<T> getHandledType();
185
186         /**
187          * Creates a parameter binding for the given target parameter.
188          *
189          * @param annotation           The annotation that was cause for the delegation to this argument binder.
190          * @param source               The intercepted source method.
191          * @param target               Tge target parameter that is subject to be bound to
192          *                             intercepting the {@code source} method.
193          * @param implementationTarget The target of the current implementation that is subject to this binding.
194          * @param assigner             An assigner that can be used for applying the binding.
195          * @param typing               The typing to apply.
196          * @return A parameter binding for the requested target method parameter.
197          */

198         ParameterBinding<?> bind(AnnotationDescription.Loadable<T> annotation,
199                                  MethodDescription source,
200                                  ParameterDescription target,
201                                  Implementation.Target implementationTarget,
202                                  Assigner assigner,
203                                  Assigner.Typing typing);
204
205         /**
206          * <p>
207          * Implements a parameter binder that binds a fixed value to a parameter with a given annotation.
208          * </p>
209          * <p>
210          * This binder is only capable to store values that can either be expressed as Java byte code or as a constant pool value. This
211          * includes primitive types, {@link String} values, {@link Class} values which can also be expressed as {@link TypeDescription}
212          * instances or method handles and method types for classes of a version at least of Java 7. The latter instances can also be
213          * expressed as unloaded {@link JavaConstant} representations.
214          * </p>
215          * <p>
216          * <b>Important</b>: When supplying a method handle or a method type, all types that are implied must be visible to the instrumented
217          * type or an {@link IllegalAccessException} will be thrown at runtime.
218          * </p>
219          *
220          * @param <S> The bound annotation's type.
221          */

222         abstract class ForFixedValue<S extends Annotation> implements ParameterBinder<S> {
223
224             /**
225              * {@inheritDoc}
226              */

227             public ParameterBinding<?> bind(AnnotationDescription.Loadable<S> annotation,
228                                             MethodDescription source,
229                                             ParameterDescription target,
230                                             Implementation.Target implementationTarget,
231                                             Assigner assigner,
232                                             Assigner.Typing typing) {
233                 Object value = bind(annotation, source, target);
234                 if (value == null) {
235                     return new ParameterBinding.Anonymous(DefaultValue.of(target.getType()));
236                 }
237                 StackManipulation stackManipulation;
238                 TypeDescription suppliedType;
239                 if (value instanceof Boolean) {
240                     stackManipulation = IntegerConstant.forValue((Boolean) value);
241                     suppliedType = TypeDescription.ForLoadedType.of(boolean.class);
242                 } else if (value instanceof Byte) {
243                     stackManipulation = IntegerConstant.forValue((Byte) value);
244                     suppliedType = TypeDescription.ForLoadedType.of(byte.class);
245                 } else if (value instanceof Short) {
246                     stackManipulation = IntegerConstant.forValue((Short) value);
247                     suppliedType = TypeDescription.ForLoadedType.of(short.class);
248                 } else if (value instanceof Character) {
249                     stackManipulation = IntegerConstant.forValue((Character) value);
250                     suppliedType = TypeDescription.ForLoadedType.of(char.class);
251                 } else if (value instanceof Integer) {
252                     stackManipulation = IntegerConstant.forValue((Integer) value);
253                     suppliedType = TypeDescription.ForLoadedType.of(int.class);
254                 } else if (value instanceof Long) {
255                     stackManipulation = LongConstant.forValue((Long) value);
256                     suppliedType = TypeDescription.ForLoadedType.of(long.class);
257                 } else if (value instanceof Float) {
258                     stackManipulation = FloatConstant.forValue((Float) value);
259                     suppliedType = TypeDescription.ForLoadedType.of(float.class);
260                 } else if (value instanceof Double) {
261                     stackManipulation = DoubleConstant.forValue((Double) value);
262                     suppliedType = TypeDescription.ForLoadedType.of(double.class);
263                 } else if (value instanceof String) {
264                     stackManipulation = new TextConstant((String) value);
265                     suppliedType = TypeDescription.STRING;
266                 } else if (value instanceof Class) {
267                     stackManipulation = ClassConstant.of(TypeDescription.ForLoadedType.of((Class<?>) value));
268                     suppliedType = TypeDescription.CLASS;
269                 } else if (value instanceof TypeDescription) {
270                     stackManipulation = ClassConstant.of((TypeDescription) value);
271                     suppliedType = TypeDescription.CLASS;
272                 } else if (JavaType.METHOD_HANDLE.isInstance(value)) {
273                     stackManipulation = new JavaConstantValue(JavaConstant.MethodHandle.ofLoaded(value));
274                     suppliedType = JavaType.METHOD_HANDLE.getTypeStub();
275                 } else if (value instanceof JavaConstant.MethodHandle) {
276                     stackManipulation = new JavaConstantValue((JavaConstant.MethodHandle) value);
277                     suppliedType = JavaType.METHOD_HANDLE.getTypeStub();
278                 } else if (JavaType.METHOD_TYPE.isInstance(value)) {
279                     stackManipulation = new JavaConstantValue(JavaConstant.MethodType.ofLoaded(value));
280                     suppliedType = JavaType.METHOD_HANDLE.getTypeStub();
281                 } else if (value instanceof JavaConstant.MethodType) {
282                     stackManipulation = new JavaConstantValue((JavaConstant.MethodType) value);
283                     suppliedType = JavaType.METHOD_HANDLE.getTypeStub();
284                 } else {
285                     throw new IllegalStateException("Not able to save in class's constant pool: " + value);
286                 }
287                 return new ParameterBinding.Anonymous(new StackManipulation.Compound(
288                         stackManipulation,
289                         assigner.assign(suppliedType.asGenericType(), target.getType(), typing)
290                 ));
291             }
292
293             /**
294              * Resolves a value for the given annotation on a parameter that is processed by a {@link net.bytebuddy.implementation.MethodDelegation}.
295              *
296              * @param annotation The annotation that triggered this binding.
297              * @param source     The method for which a delegation is currently bound.
298              * @param target     The parameter for which a value is bound.
299              * @return The constant pool value that is bound to this parameter or {@code nullfor binding this value.
300              */

301             protected abstract Object bind(AnnotationDescription.Loadable<S> annotation, MethodDescription source, ParameterDescription target);
302
303             /**
304              * <p>
305              * A parameter binder that binds a fixed value to a parameter annotation when using a {@link net.bytebuddy.implementation.MethodDelegation}.
306              * </p>
307              * <p>
308              * This binder is only capable to store
309              * values that can either be expressed as Java byte code or as a constant pool value. This includes primitive types, {@link String} values,
310              * {@link Class} values which can also be expressed as {@link TypeDescription} instances or method handles and method types for classes of
311              * a version at least of Java 7. The latter instances can also be expressed as unloaded {@link JavaConstant} representations.
312              * </p>
313              *
314              * @param <U> The bound annotation's type.
315              */

316             @HashCodeAndEqualsPlugin.Enhance
317             public static class OfConstant<U extends Annotation> extends ForFixedValue<U> {
318
319                 /**
320                  * The type of the annotation that is bound by this binder.
321                  */

322                 private final Class<U> type;
323
324                 /**
325                  * The value that is assigned to any annotated parameter.
326                  */

327                 @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
328                 private final Object value;
329
330                 /**
331                  * Creates a binder for binding a fixed value to a parameter annotated with the given annotation.
332                  *
333                  * @param type  The type of the annotation that is bound by this binder.
334                  * @param value The value that is assigned to any annotated parameter.
335                  */

336                 protected OfConstant(Class<U> type, Object value) {
337                     this.type = type;
338                     this.value = value;
339                 }
340
341                 /**
342                  * Creates a binder for binding a fixed value to a given annotation.
343                  *
344                  * @param type  The type of the annotation that is bound by this binder.
345                  * @param value The value that is assigned to any annotated parameter.
346                  * @param <V>   The bound annotation's type.
347                  * @return A parameter binder that binds the given annotation to the supplied value.
348                  */

349                 public static <V extends Annotation> ParameterBinder<V> of(Class<V> type, Object value) {
350                     return new OfConstant<V>(type, value);
351                 }
352
353                 /**
354                  * {@inheritDoc}
355                  */

356                 public Class<U> getHandledType() {
357                     return type;
358                 }
359
360                 @Override
361                 protected Object bind(AnnotationDescription.Loadable<U> annotation, MethodDescription source, ParameterDescription target) {
362                     return value;
363                 }
364             }
365         }
366
367         /**
368          * A parameter binder that binds a field's value.
369          *
370          * @param <S> The {@link java.lang.annotation.Annotation#annotationType()} handled by this parameter binder.
371          */

372         abstract class ForFieldBinding<S extends Annotation> implements ParameterBinder<S> {
373
374             /**
375              * Indicates that a name should be extracted from an accessor method.
376              */

377             protected static final String BEAN_PROPERTY = "";
378
379             /**
380              * Resolves a field locator for a potential accessor method.
381              *
382              * @param fieldLocator      The field locator to use.
383              * @param methodDescription The method description that is the potential accessor.
384              * @return A resolution for a field locator.
385              */

386             private static FieldLocator.Resolution resolveAccessor(FieldLocator fieldLocator, MethodDescription methodDescription) {
387                 String fieldName;
388                 if (isSetter().matches(methodDescription)) {
389                     fieldName = methodDescription.getInternalName().substring(3);
390                 } else if (isGetter().matches(methodDescription)) {
391                     fieldName = methodDescription.getInternalName().substring(methodDescription.getInternalName().startsWith("is") ? 2 : 3);
392                 } else {
393                     return FieldLocator.Resolution.Illegal.INSTANCE;
394                 }
395                 return fieldLocator.locate(Character.toLowerCase(fieldName.charAt(0)) + fieldName.substring(1));
396             }
397
398             /**
399              * {@inheritDoc}
400              */

401             public ParameterBinding<?> bind(AnnotationDescription.Loadable<S> annotation,
402                                             MethodDescription source,
403                                             ParameterDescription target,
404                                             Implementation.Target implementationTarget,
405                                             Assigner assigner,
406                                             Assigner.Typing typing) {
407                 if (!declaringType(annotation).represents(void.class)) {
408                     if (declaringType(annotation).isPrimitive() || declaringType(annotation).isArray()) {
409                         throw new IllegalStateException("A primitive type or array type cannot declare a field: " + source);
410                     } else if (!implementationTarget.getInstrumentedType().isAssignableTo(declaringType(annotation))) {
411                         return MethodDelegationBinder.ParameterBinding.Illegal.INSTANCE;
412                     }
413                 }
414                 FieldLocator fieldLocator = declaringType(annotation).represents(void.class)
415                         ? new FieldLocator.ForClassHierarchy(implementationTarget.getInstrumentedType())
416                         : new FieldLocator.ForExactType(declaringType(annotation), implementationTarget.getInstrumentedType());
417                 FieldLocator.Resolution resolution = fieldName(annotation).equals(BEAN_PROPERTY)
418                         ? resolveAccessor(fieldLocator, source)
419                         : fieldLocator.locate(fieldName(annotation));
420                 return resolution.isResolved() && !(source.isStatic() && !resolution.getField().isStatic())
421                         ? bind(resolution.getField(), annotation, source, target, implementationTarget, assigner)
422                         : ParameterBinding.Illegal.INSTANCE;
423             }
424
425             /**
426              * Extracts the field name from an annotation.
427              *
428              * @param annotation The annotation from which to extract the field name.
429              * @return The field name defined by the handled annotation.
430              */

431             protected abstract String fieldName(AnnotationDescription.Loadable<S> annotation);
432
433             /**
434              * Extracts the declaring type from an annotation.
435              *
436              * @param annotation The annotation from which to extract the declaring type.
437              * @return The declaring type defined by the handled annotation.
438              */

439             protected abstract TypeDescription declaringType(AnnotationDescription.Loadable<S> annotation);
440
441             /**
442              * Creates a parameter binding for the given target parameter.
443              *
444              * @param fieldDescription     The field for which this binder binds a value.
445              * @param annotation           The annotation that was cause for the delegation to this argument binder.
446              * @param source               The intercepted source method.
447              * @param target               Tge target parameter that is subject to be bound to
448              *                             intercepting the {@code source} method.
449              * @param implementationTarget The target of the current implementation that is subject to this binding.
450              * @param assigner             An assigner that can be used for applying the binding.
451              * @return A parameter binding for the requested target method parameter.
452              */

453             protected abstract ParameterBinding<?> bind(FieldDescription fieldDescription,
454                                                         AnnotationDescription.Loadable<S> annotation,
455                                                         MethodDescription source,
456                                                         ParameterDescription target,
457                                                         Implementation.Target implementationTarget,
458                                                         Assigner assigner);
459         }
460     }
461
462     /**
463      * A delegation processor is a helper class for a
464      * {@link net.bytebuddy.implementation.bind.annotation.TargetMethodAnnotationDrivenBinder}
465      * for performing its actual logic. By outsourcing this logic to this helper class, a cleaner implementation
466      * can be provided.
467      */

468     @HashCodeAndEqualsPlugin.Enhance
469     protected static class DelegationProcessor {
470
471         /**
472          * A map of registered annotation types to the binder that is responsible for binding a parameter
473          * that is annotated with the given annotation.
474          */

475         private final Map<? extends TypeDescription, ? extends ParameterBinder<?>> parameterBinders;
476
477         /**
478          * Creates a new delegation processor.
479          *
480          * @param parameterBinders A mapping of parameter binders by their handling type.
481          */

482         protected DelegationProcessor(Map<? extends TypeDescription, ? extends ParameterBinder<?>> parameterBinders) {
483             this.parameterBinders = parameterBinders;
484         }
485
486         /**
487          * Creates a new delegation processor.
488          *
489          * @param parameterBinders A list of parameter binder delegates. Each such delegate is responsible for creating
490          *                         a {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.ParameterBinding}
491          *                         for a specific annotation.
492          * @return A corresponding delegation processor.
493          */

494         protected static DelegationProcessor of(List<? extends ParameterBinder<?>> parameterBinders) {
495             Map<TypeDescription, ParameterBinder<?>> parameterBinderMap = new HashMap<TypeDescription, ParameterBinder<?>>();
496             for (ParameterBinder<?> parameterBinder : parameterBinders) {
497                 if (parameterBinderMap.put(TypeDescription.ForLoadedType.of(parameterBinder.getHandledType()), parameterBinder) != null) {
498                     throw new IllegalArgumentException("Attempt to bind two handlers to " + parameterBinder.getHandledType());
499                 }
500             }
501             return new DelegationProcessor(parameterBinderMap);
502         }
503
504         /**
505          * Locates a handler which is responsible for processing the given parameter. If no explicit handler can
506          * be located, a fallback handler is provided.
507          *
508          * @param target The target parameter being handled.
509          * @return A handler for processing the parameter with the given annotations.
510          */

511         protected Handler prepare(ParameterDescription target) {
512             Assigner.Typing typing = RuntimeType.Verifier.check(target);
513             Handler handler = new Handler.Unbound(target, typing);
514             for (AnnotationDescription annotation : target.getDeclaredAnnotations()) {
515                 ParameterBinder<?> parameterBinder = parameterBinders.get(annotation.getAnnotationType());
516                 if (parameterBinder != null && handler.isBound()) {
517                     throw new IllegalStateException("Ambiguous binding for parameter annotated with two handled annotation types");
518                 } else if (parameterBinder != null /* && !handler.isBound() */) {
519                     handler = Handler.Bound.of(target, parameterBinder, annotation, typing);
520                 }
521             }
522             return handler;
523         }
524
525         /**
526          * A handler is responsible for processing a parameter's binding.
527          */

528         protected interface Handler {
529
530             /**
531              * Indicates if this handler was explicitly bound.
532              *
533              * @return {@code trueif this handler was explicitly bound.
534              */

535             boolean isBound();
536
537             /**
538              * Handles a parameter binding.
539              *
540              * @param source               The intercepted source method.
541              * @param implementationTarget The target of the current implementation.
542              * @param assigner             The assigner to use.
543              * @return A parameter binding that reflects the given arguments.
544              */

545             ParameterBinding<?> bind(MethodDescription source, Implementation.Target implementationTarget, Assigner assigner);
546
547             /**
548              * An unbound handler is a fallback for returning an illegal binding for parameters for which no parameter
549              * binder could be located.
550              */

551             @HashCodeAndEqualsPlugin.Enhance
552             class Unbound implements Handler {
553
554                 /**
555                  * The target parameter being handled.
556                  */

557                 private final ParameterDescription target;
558
559                 /**
560                  * The typing to apply.
561                  */

562                 private final Assigner.Typing typing;
563
564                 /**
565                  * Creates a new unbound handler.
566                  *
567                  * @param target The target parameter being handled.
568                  * @param typing The typing to apply.
569                  */

570                 protected Unbound(ParameterDescription target, Assigner.Typing typing) {
571                     this.target = target;
572                     this.typing = typing;
573                 }
574
575                 /**
576                  * {@inheritDoc}
577                  */

578                 public boolean isBound() {
579                     return false;
580                 }
581
582                 /**
583                  * {@inheritDoc}
584                  */

585                 public ParameterBinding<?> bind(MethodDescription source, Implementation.Target implementationTarget, Assigner assigner) {
586                     return Argument.Binder.INSTANCE.bind(AnnotationDescription.ForLoadedAnnotation.<Argument>of(new DefaultArgument(target.getIndex())),
587                             source,
588                             target,
589                             implementationTarget,
590                             assigner,
591                             typing);
592                 }
593
594                 /**
595                  * A default implementation of an {@link net.bytebuddy.implementation.bind.annotation.Argument} annotation.
596                  */

597                 protected static class DefaultArgument implements Argument {
598
599                     /**
600                      * The name of the value annotation parameter.
601                      */

602                     private static final String VALUE = "value";
603
604                     /**
605                      * The name of the value binding mechanic parameter.
606                      */

607                     private static final String BINDING_MECHANIC = "bindingMechanic";
608
609                     /**
610                      * The index of the source method parameter to be bound.
611                      */

612                     private final int parameterIndex;
613
614                     /**
615                      * Creates a new instance of an argument annotation.
616                      *
617                      * @param parameterIndex The index of the source method parameter to be bound.
618                      */

619                     protected DefaultArgument(int parameterIndex) {
620                         this.parameterIndex = parameterIndex;
621                     }
622
623                     /**
624                      * {@inheritDoc}
625                      */

626                     public int value() {
627                         return parameterIndex;
628                     }
629
630                     /**
631                      * {@inheritDoc}
632                      */

633                     public BindingMechanic bindingMechanic() {
634                         return BindingMechanic.UNIQUE;
635                     }
636
637                     /**
638                      * {@inheritDoc}
639                      */

640                     public Class<Argument> annotationType() {
641                         return Argument.class;
642                     }
643
644                     @Override
645                     public int hashCode() {
646                         return ((127 * BINDING_MECHANIC.hashCode()) ^ BindingMechanic.UNIQUE.hashCode()) + ((127 * VALUE.hashCode()) ^ parameterIndex);
647                     }
648
649                     @Override
650                     public boolean equals(Object other) {
651                         return this == other || other instanceof Argument && parameterIndex == ((Argument) other).value();
652                     }
653
654                     @Override
655                     public String toString() {
656                         return "@" + Argument.class.getName()
657                                 + "(bindingMechanic=" + BindingMechanic.UNIQUE.toString()
658                                 + ", value=" + parameterIndex + ")";
659                     }
660                 }
661             }
662
663             /**
664              * A bound handler represents an unambiguous parameter binder that was located for a given array of
665              * annotations.
666              *
667              * @param <T> The annotation type of a given handler.
668              */

669             @HashCodeAndEqualsPlugin.Enhance
670             class Bound<T extends Annotation> implements Handler {
671
672                 /**
673                  * The target parameter being handled.
674                  */

675                 private final ParameterDescription target;
676
677                 /**
678                  * The parameter binder that is actually responsible for binding the parameter.
679                  */

680                 private final ParameterBinder<T> parameterBinder;
681
682                 /**
683                  * The annotation value that lead to the binding of this handler.
684                  */

685                 private final AnnotationDescription.Loadable<T> annotation;
686
687                 /**
688                  * The typing to apply.
689                  */

690                 private final Assigner.Typing typing;
691
692                 /**
693                  * Creates a new bound handler.
694                  *
695                  * @param target          The target parameter being handled.
696                  * @param parameterBinder The parameter binder that is actually responsible for binding the parameter.
697                  * @param annotation      The annotation value that lead to the binding of this handler.
698                  * @param typing          The typing to apply.
699                  */

700                 protected Bound(ParameterDescription target,
701                                 ParameterBinder<T> parameterBinder,
702                                 AnnotationDescription.Loadable<T> annotation,
703                                 Assigner.Typing typing) {
704                     this.target = target;
705                     this.parameterBinder = parameterBinder;
706                     this.annotation = annotation;
707                     this.typing = typing;
708                 }
709
710                 /**
711                  * Creates a handler for a given annotation.
712                  *
713                  * @param target          The target parameter being handled.
714                  * @param parameterBinder The parameter binder that should process an annotation.
715                  * @param annotation      An annotation instance that can be understood by this parameter binder.
716                  * @param typing          The typing to apply.
717                  * @return A handler for processing the given annotation.
718                  */

719                 @SuppressWarnings("unchecked")
720                 protected static Handler of(ParameterDescription target,
721                                             ParameterBinder<?> parameterBinder,
722                                             AnnotationDescription annotation,
723                                             Assigner.Typing typing) {
724                     return new Bound<Annotation>(target,
725                             (ParameterBinder<Annotation>) parameterBinder,
726                             (AnnotationDescription.Loadable<Annotation>) annotation.prepare(parameterBinder.getHandledType()),
727                             typing);
728                 }
729
730                 /**
731                  * {@inheritDoc}
732                  */

733                 public boolean isBound() {
734                     return true;
735                 }
736
737                 /**
738                  * {@inheritDoc}
739                  */

740                 public ParameterBinding<?> bind(MethodDescription source, Implementation.Target implementationTarget, Assigner assigner) {
741                     return parameterBinder.bind(annotation,
742                             source,
743                             target,
744                             implementationTarget,
745                             assigner,
746                             typing);
747                 }
748             }
749         }
750     }
751 }
752