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;
17
18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
20 import net.bytebuddy.description.method.MethodDescription;
21 import net.bytebuddy.description.type.TypeDescription;
22 import net.bytebuddy.implementation.Implementation;
23 import net.bytebuddy.implementation.bind.annotation.BindingPriority;
24 import net.bytebuddy.implementation.bytecode.Removal;
25 import net.bytebuddy.implementation.bytecode.StackManipulation;
26 import net.bytebuddy.implementation.bytecode.assign.Assigner;
27 import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
28 import net.bytebuddy.implementation.bytecode.member.MethodReturn;
29 import net.bytebuddy.utility.CompoundList;
30 import net.bytebuddy.jar.asm.MethodVisitor;
31
32 import java.io.PrintStream;
33 import java.util.*;
34
35 /**
36  * A method delegation binder is responsible for creating a method binding for a <i>source method</i> to a
37  * <i>target method</i>. Such a binding allows to implement the source method by calling the target method.
38  * <p>&nbsp;</p>
39  * Usually, an implementation will attempt to bind a specific source method to a set of target method candidates
40  * where all legal bindings are considered for binding. To chose a specific candidate, an
41  * {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.AmbiguityResolver}
42  * will be consulted for selecting a <i>best</i> binding.
43  */

44 public interface MethodDelegationBinder {
45
46     /**
47      * Compiles this method delegation binder for a target method.
48      *
49      * @param candidate The target method to bind.
50      * @return A compiled target for binding.
51      */

52     Record compile(MethodDescription candidate);
53
54     /**
55      * A method delegation that was compiled to a target method.
56      */

57     interface Record {
58
59         /**
60          * Attempts a binding of a source method to this compiled target.
61          *
62          * @param implementationTarget The target of the current implementation onto which this binding is to be applied.
63          * @param source               The method that is to be bound to the {@code target} method.
64          * @param terminationHandler   The termination handler to apply.
65          * @param methodInvoker        The method invoker to use.
66          * @param assigner             The assigner to use.
67          * @return A binding representing this attempt to bind the {@code source} method to the {@code target} method.
68          */

69         MethodBinding bind(Implementation.Target implementationTarget,
70                            MethodDescription source,
71                            TerminationHandler terminationHandler,
72                            MethodInvoker methodInvoker,
73                            Assigner assigner);
74
75         /**
76          * A compiled method delegation binder that only yields illegal bindings.
77          */

78         enum Illegal implements Record {
79
80             /**
81              * The singleton instance.
82              */

83             INSTANCE;
84
85             /**
86              * {@inheritDoc}
87              */

88             public MethodBinding bind(Implementation.Target implementationTarget,
89                                       MethodDescription source,
90                                       TerminationHandler terminationHandler,
91                                       MethodInvoker methodInvoker,
92                                       Assigner assigner) {
93                 return MethodBinding.Illegal.INSTANCE;
94             }
95         }
96     }
97
98     /**
99      * Implementations are used as delegates for invoking a method that was bound
100      * using a {@link net.bytebuddy.implementation.bind.MethodDelegationBinder}.
101      */

102     interface MethodInvoker {
103
104         /**
105          * Creates a method invocation for a given method.
106          *
107          * @param methodDescription The method to be invoked.
108          * @return A stack manipulation encapsulating this method invocation.
109          */

110         StackManipulation invoke(MethodDescription methodDescription);
111
112         /**
113          * A simple method invocation that merely uses the most general form of method invocation as provided by
114          * {@link net.bytebuddy.implementation.bytecode.member.MethodInvocation}.
115          */

116         enum Simple implements MethodInvoker {
117
118             /**
119              * The singleton instance.
120              */

121             INSTANCE;
122
123             /**
124              * {@inheritDoc}
125              */

126             public StackManipulation invoke(MethodDescription methodDescription) {
127                 return MethodInvocation.invoke(methodDescription);
128             }
129         }
130
131         /**
132          * A method invocation that enforces a virtual invocation that is dispatched on a given type.
133          */

134         @HashCodeAndEqualsPlugin.Enhance
135         class Virtual implements MethodInvoker {
136
137             /**
138              * The type on which a method should be invoked virtually.
139              */

140             private final TypeDescription typeDescription;
141
142             /**
143              * Creates an immutable method invoker that dispatches all methods on a given type.
144              *
145              * @param typeDescription The type on which the method is invoked by virtual invocation.
146              */

147             public Virtual(TypeDescription typeDescription) {
148                 this.typeDescription = typeDescription;
149             }
150
151             /**
152              * {@inheritDoc}
153              */

154             public StackManipulation invoke(MethodDescription methodDescription) {
155                 return MethodInvocation.invoke(methodDescription).virtual(typeDescription);
156             }
157         }
158     }
159
160     /**
161      * A binding attempt for a single parameter. Implementations of this type are a suggestion of composing a
162      * {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.MethodBinding}
163      * by using a
164      * {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.MethodBinding.Builder}.
165      * However, method bindings can also be composed without this type which is merely a suggestion.
166      *
167      * @param <T> The type of the identification token for this parameter binding.
168      */

169     interface ParameterBinding<T> extends StackManipulation {
170
171         /**
172          * Returns an identification token for this binding.
173          *
174          * @return An identification token unique to this binding.
175          */

176         T getIdentificationToken();
177
178         /**
179          * A singleton representation of an illegal binding for a method parameter. An illegal binding usually
180          * suggests that a source method cannot be bound to a specific target method.
181          */

182         enum Illegal implements ParameterBinding<Void> {
183
184             /**
185              * The singleton instance.
186              */

187             INSTANCE;
188
189             /**
190              * {@inheritDoc}
191              */

192             public Void getIdentificationToken() {
193                 throw new IllegalStateException("An illegal binding does not define an identification token");
194             }
195
196             /**
197              * {@inheritDoc}
198              */

199             public boolean isValid() {
200                 return false;
201             }
202
203             /**
204              * {@inheritDoc}
205              */

206             public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
207                 throw new IllegalStateException("An illegal parameter binding must not be applied");
208             }
209         }
210
211         /**
212          * An anonymous binding of a target method parameter.
213          */

214         @HashCodeAndEqualsPlugin.Enhance
215         class Anonymous implements ParameterBinding<Object> {
216
217             /**
218              * A pseudo-token that is not exposed and therefore anonymous.
219              */

220             @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.IGNORE)
221             private final Object anonymousToken;
222
223             /**
224              * The stack manipulation that represents the loading of the parameter binding onto the stack.
225              */

226             private final StackManipulation delegate;
227
228             /**
229              * Creates a new, anonymous parameter binding.
230              *
231              * @param delegate The stack manipulation that is responsible for loading the parameter value for this
232              *                 target method parameter onto the stack.
233              */

234             public Anonymous(StackManipulation delegate) {
235                 this.delegate = delegate;
236                 anonymousToken = new Object();
237             }
238
239             /**
240              * {@inheritDoc}
241              */

242             public Object getIdentificationToken() {
243                 return anonymousToken;
244             }
245
246             /**
247              * {@inheritDoc}
248              */

249             public boolean isValid() {
250                 return delegate.isValid();
251             }
252
253             /**
254              * {@inheritDoc}
255              */

256             public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
257                 return delegate.apply(methodVisitor, implementationContext);
258             }
259         }
260
261         /**
262          * A uniquely identifiable parameter binding for a target method. Such bindings are usually later processed by
263          * a {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.AmbiguityResolver}
264          * in order to resolve binding conflicts between several bindable target methods to the same source method.
265          *
266          * @param <T> The type of the identification token.
267          * @see net.bytebuddy.implementation.bind.MethodDelegationBinder.AmbiguityResolver
268          */

269         @HashCodeAndEqualsPlugin.Enhance
270         class Unique<T> implements ParameterBinding<T> {
271
272             /**
273              * The token that identifies this parameter binding as unique.
274              */

275             private final T identificationToken;
276
277             /**
278              * The stack manipulation that represents the loading of the parameter binding onto the stack.
279              */

280             private final StackManipulation delegate;
281
282             /**
283              * Creates a new unique parameter binding representant.
284              *
285              * @param delegate            The stack manipulation that loads the argument for this parameter onto the operand stack.
286              * @param identificationToken The token used for identifying this parameter binding.
287              */

288             public Unique(StackManipulation delegate, T identificationToken) {
289                 this.delegate = delegate;
290                 this.identificationToken = identificationToken;
291             }
292
293             /**
294              * A factory method for creating a unique binding that infers the tokens type.
295              *
296              * @param delegate            The stack manipulation delegate.
297              * @param identificationToken The identification token.
298              * @param <S>                 The type of the identification token.
299              * @return A new instance representing this unique binding.
300              */

301             public static <S> Unique<S> of(StackManipulation delegate, S identificationToken) {
302                 return new Unique<S>(delegate, identificationToken);
303             }
304
305             /**
306              * {@inheritDoc}
307              */

308             public T getIdentificationToken() {
309                 return identificationToken;
310             }
311
312             /**
313              * {@inheritDoc}
314              */

315             public boolean isValid() {
316                 return delegate.isValid();
317             }
318
319             /**
320              * {@inheritDoc}
321              */

322             public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
323                 return delegate.apply(methodVisitor, implementationContext);
324             }
325         }
326     }
327
328     /**
329      * A binding attempt created by a
330      * {@link net.bytebuddy.implementation.bind.MethodDelegationBinder}.
331      */

332     interface MethodBinding extends StackManipulation {
333
334         /**
335          * Returns the target method's parameter index for a given parameter binding token.
336          * <p>&nbsp;</p>
337          * A binding token can be any object
338          * that implements valid {@link Object#hashCode()} and {@link Object#equals(Object)} methods in order
339          * to look up a given binding. This way, two bindings can be evaluated of having performed a similar type of
340          * binding such that these bindings can be compared and a dominant binding can be identified by an
341          * {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.AmbiguityResolver}.
342          * Furthermore, a binding is implicitly required to insure the uniqueness of such a parameter binding.
343          *
344          * @param parameterBindingToken A token which is used to identify a specific unique binding for a given parameter
345          *                              of the target method.
346          * @return The target method's parameter index of this binding or {@code nullif no such argument binding
347          * was applied for this binding.
348          */

349         Integer getTargetParameterIndex(Object parameterBindingToken);
350
351         /**
352          * Returns the target method of the method binding attempt.
353          *
354          * @return The target method to which the
355          */

356         MethodDescription getTarget();
357
358         /**
359          * Representation of an attempt to bind a source method to a target method that is not applicable.
360          *
361          * @see net.bytebuddy.implementation.bind.MethodDelegationBinder
362          */

363         enum Illegal implements MethodBinding {
364
365             /**
366              * The singleton instance.
367              */

368             INSTANCE;
369
370             /**
371              * {@inheritDoc}
372              */

373             public Integer getTargetParameterIndex(Object parameterBindingToken) {
374                 throw new IllegalStateException("Method is not bound");
375             }
376
377             /**
378              * {@inheritDoc}
379              */

380             public MethodDescription getTarget() {
381                 throw new IllegalStateException("Method is not bound");
382             }
383
384             /**
385              * {@inheritDoc}
386              */

387             public boolean isValid() {
388                 return false;
389             }
390
391             /**
392              * {@inheritDoc}
393              */

394             public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
395                 throw new IllegalStateException("Cannot delegate to an unbound method");
396             }
397         }
398
399         /**
400          * A mutable builder that allows to compose a
401          * {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.MethodBinding}
402          * by adding parameter bindings incrementally.
403          */

404         class Builder {
405
406             /**
407              * The method invoker for invoking the actual method that is bound.
408              */

409             private final MethodInvoker methodInvoker;
410
411             /**
412              * The target method that for which a binding is to be constructed by this builder..
413              */

414             private final MethodDescription candidate;
415
416             /**
417              * The current list of stack manipulations for loading values for each parameter onto the operand stack.
418              */

419             private final List<StackManipulation> parameterStackManipulations;
420
421             /**
422              * A mapping of identification tokens to the parameter index they were bound for.
423              */

424             private final LinkedHashMap<Object, Integer> registeredTargetIndices;
425
426             /**
427              * The index of the next parameter that is to be bound.
428              */

429             private int nextParameterIndex;
430
431             /**
432              * Creates a new builder for the binding of a given method.
433              *
434              * @param methodInvoker The method invoker that is used to create the method invocation of the {@code target} method.
435              * @param candidate     The target method that is target of the binding.
436              */

437             public Builder(MethodInvoker methodInvoker, MethodDescription candidate) {
438                 this.methodInvoker = methodInvoker;
439                 this.candidate = candidate;
440                 parameterStackManipulations = new ArrayList<StackManipulation>(candidate.getParameters().size());
441                 registeredTargetIndices = new LinkedHashMap<Object, Integer>();
442                 nextParameterIndex = 0;
443             }
444
445             /**
446              * Appends a stack manipulation for the next parameter of the target method.
447              *
448              * @param parameterBinding A binding representing the next subsequent parameter of the method.
449              * @return {@code falseif the {@code parameterBindingToken} was already bound. A conflicting binding should
450              * usually abort the attempt of binding a method and this {@code Builder} should be discarded.
451              */

452             public boolean append(ParameterBinding<?> parameterBinding) {
453                 parameterStackManipulations.add(parameterBinding);
454                 return registeredTargetIndices.put(parameterBinding.getIdentificationToken(), nextParameterIndex++) == null;
455             }
456
457             /**
458              * Creates a binding that represents the bindings collected by this {@code Builder}.
459              *
460              * @param terminatingManipulation A stack manipulation that is applied after the method invocation.
461              * @return A binding representing the parameter bindings collected by this builder.
462              */

463             public MethodBinding build(StackManipulation terminatingManipulation) {
464                 if (candidate.getParameters().size() != nextParameterIndex) {
465                     throw new IllegalStateException("The number of parameters bound does not equal the target's number of parameters");
466                 }
467                 return new Build(candidate,
468                         registeredTargetIndices,
469                         methodInvoker.invoke(candidate),
470                         parameterStackManipulations,
471                         terminatingManipulation);
472             }
473
474             /**
475              * A method binding that was created by a
476              * {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.MethodBinding.Builder}.
477              */

478             @HashCodeAndEqualsPlugin.Enhance
479             protected static class Build implements MethodBinding {
480
481                 /**
482                  * The target method this binding represents.
483                  */

484                 private final MethodDescription target;
485
486                 /**
487                  * A map of identification tokens to the indices of their binding parameters.
488                  */

489                 private final Map<?, Integer> registeredTargetIndices;
490
491                 /**
492                  * A stack manipulation that represents the actual method invocation.
493                  */

494                 private final StackManipulation methodInvocation;
495
496                 /**
497                  * A list of manipulations that each represent the loading of a parameter value onto the operand stack.
498                  */

499                 private final List<StackManipulation> parameterStackManipulations;
500
501                 /**
502                  * The stack manipulation that is applied after the method invocation.
503                  */

504                 private final StackManipulation terminatingStackManipulation;
505
506                 /**
507                  * Creates a new method binding.
508                  *
509                  * @param target                       The target method this binding represents.
510                  * @param registeredTargetIndices      A map of identification tokens to the indices of their binding
511                  *                                     parameters.
512                  * @param methodInvocation             A stack manipulation that represents the actual method invocation.
513                  * @param parameterStackManipulations  A list of manipulations that each represent the loading of a
514                  *                                     parameter value onto the operand stack.
515                  * @param terminatingStackManipulation The stack manipulation that is applied after the method invocation.
516                  */

517                 protected Build(MethodDescription target,
518                                 Map<?, Integer> registeredTargetIndices,
519                                 StackManipulation methodInvocation,
520                                 List<StackManipulation> parameterStackManipulations,
521                                 StackManipulation terminatingStackManipulation) {
522                     this.target = target;
523                     this.registeredTargetIndices = new HashMap<Object, Integer>(registeredTargetIndices);
524                     this.methodInvocation = methodInvocation;
525                     this.parameterStackManipulations = new ArrayList<StackManipulation>(parameterStackManipulations);
526                     this.terminatingStackManipulation = terminatingStackManipulation;
527                 }
528
529                 /**
530                  * {@inheritDoc}
531                  */

532                 public boolean isValid() {
533                     boolean result = methodInvocation.isValid() && terminatingStackManipulation.isValid();
534                     Iterator<StackManipulation> assignment = parameterStackManipulations.iterator();
535                     while (result && assignment.hasNext()) {
536                         result = assignment.next().isValid();
537                     }
538                     return result;
539                 }
540
541                 /**
542                  * {@inheritDoc}
543                  */

544                 public Integer getTargetParameterIndex(Object parameterBindingToken) {
545                     return registeredTargetIndices.get(parameterBindingToken);
546                 }
547
548                 /**
549                  * {@inheritDoc}
550                  */

551                 public MethodDescription getTarget() {
552                     return target;
553                 }
554
555                 /**
556                  * {@inheritDoc}
557                  */

558                 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
559                     return new Compound(
560                             CompoundList.of(parameterStackManipulations, Arrays.asList(methodInvocation, terminatingStackManipulation))
561                     ).apply(methodVisitor, implementationContext);
562                 }
563             }
564         }
565     }
566
567     /**
568      * A binding resolver is responsible to choose a method binding between several possible candidates.
569      */

570     interface BindingResolver {
571
572         /**
573          * Resolves a method binding for the {@code source} method.
574          *
575          * @param ambiguityResolver The ambiguity resolver to use.
576          * @param source            The source method being bound.
577          * @param targets           The possible target candidates. The list contains at least one element.
578          * @return The method binding that was chosen.
579          */

580         MethodBinding resolve(AmbiguityResolver ambiguityResolver, MethodDescription source, List<MethodBinding> targets);
581
582         /**
583          * A default implementation of a binding resolver that fully relies on an {@link AmbiguityResolver}.
584          */

585         enum Default implements BindingResolver {
586
587             /**
588              * The singleton instance.
589              */

590             INSTANCE;
591
592             /**
593              * Represents the index of the only value of two elements in a list.
594              */

595             private static final int ONLY = 0;
596
597             /**
598              * Represents the index of the left value of two elements in a list.
599              */

600             private static final int LEFT = 0;
601
602             /**
603              * Represents the index of the right value of two elements in a list.
604              */

605             private static final int RIGHT = 1;
606
607             /**
608              * {@inheritDoc}
609              */

610             public MethodBinding resolve(AmbiguityResolver ambiguityResolver, MethodDescription source, List<MethodBinding> targets) {
611                 return doResolve(ambiguityResolver, source, new ArrayList<MethodBinding>(targets));
612             }
613
614             /**
615              * Resolves a method binding for the {@code source} method.
616              *
617              * @param ambiguityResolver The ambiguity resolver to use.
618              * @param source            The source method being bound.
619              * @param targets           The possible target candidates. The list contains at least one element and is mutable.
620              * @return The method binding that was chosen.
621              */

622             private MethodBinding doResolve(AmbiguityResolver ambiguityResolver, MethodDescription source, List<MethodBinding> targets) {
623                 switch (targets.size()) {
624                     case 1:
625                         return targets.get(ONLY);
626                     case 2: {
627                         MethodBinding left = targets.get(LEFT);
628                         MethodBinding right = targets.get(RIGHT);
629                         switch (ambiguityResolver.resolve(source, left, right)) {
630                             case LEFT:
631                                 return left;
632                             case RIGHT:
633                                 return right;
634                             case AMBIGUOUS:
635                             case UNKNOWN:
636                                 throw new IllegalArgumentException("Cannot resolve ambiguous delegation of " + source + " to " + left.getTarget() + " or " + right.getTarget());
637                             default:
638                                 throw new AssertionError();
639                         }
640                     }
641                     default/* case 3+: */ {
642                         MethodBinding left = targets.get(LEFT);
643                         MethodBinding right = targets.get(RIGHT);
644                         switch (ambiguityResolver.resolve(source, left, right)) {
645                             case LEFT:
646                                 targets.remove(RIGHT);
647                                 return doResolve(ambiguityResolver, source, targets);
648                             case RIGHT:
649                                 targets.remove(LEFT);
650                                 return doResolve(ambiguityResolver, source, targets);
651                             case AMBIGUOUS:
652                             case UNKNOWN:
653                                 targets.remove(RIGHT); // Remove right element first due to index alteration!
654                                 targets.remove(LEFT);
655                                 MethodBinding subResult = doResolve(ambiguityResolver, source, targets);
656                                 switch (ambiguityResolver.resolve(source, left, subResult).merge(ambiguityResolver.resolve(source, right, subResult))) {
657                                     case RIGHT:
658                                         return subResult;
659                                     case LEFT:
660                                     case AMBIGUOUS:
661                                     case UNKNOWN:
662                                         throw new IllegalArgumentException("Cannot resolve ambiguous delegation of " + source + " to " + left.getTarget() + " or " + right.getTarget());
663                                     default:
664                                         throw new AssertionError();
665                                 }
666                             default:
667                                 throw new IllegalStateException("Unexpected amount of targets: " + targets.size());
668                         }
669                     }
670                 }
671             }
672         }
673
674         /**
675          * A binding resolver that only binds a method if it has a unique binding.
676          */

677         enum Unique implements BindingResolver {
678
679             /**
680              * The singleton instance.
681              */

682             INSTANCE;
683
684             /**
685              * Indicates the first index of a list only containing one element.
686              */

687             private static final int ONLY = 0;
688
689             /**
690              * {@inheritDoc}
691              */

692             public MethodBinding resolve(AmbiguityResolver ambiguityResolver, MethodDescription source, List<MethodBinding> targets) {
693                 if (targets.size() == 1) {
694                     return targets.get(ONLY);
695                 } else {
696                     throw new IllegalStateException(source + " allowed for more than one binding: " + targets);
697                 }
698             }
699         }
700
701         /**
702          * Binds a method using another resolver and prints the selected binding to a {@link PrintStream}.
703          */

704         @HashCodeAndEqualsPlugin.Enhance
705         class StreamWriting implements BindingResolver {
706
707             /**
708              * The delegate binding resolver.
709              */

710             private final BindingResolver delegate;
711
712             /**
713              * The print stream to bind write the chosen binding to.
714              */

715             private final PrintStream printStream;
716
717             /**
718              * Creates a new stream writing binding resolver.
719              *
720              * @param delegate    The delegate binding resolver.
721              * @param printStream The print stream to bind write the chosen binding to.
722              */

723             public StreamWriting(BindingResolver delegate, PrintStream printStream) {
724                 this.delegate = delegate;
725                 this.printStream = printStream;
726             }
727
728             /**
729              * Creates a binding resolver that writes results to {@link System#out} and delegates to the {@link Default} resolver.
730              *
731              * @return An appropriate binding resolver.
732              */

733             public static BindingResolver toSystemOut() {
734                 return toSystemOut(Default.INSTANCE);
735             }
736
737             /**
738              * Creates a binding resolver that writes results to {@link System#out} and delegates to the {@link Default} resolver.
739              *
740              * @param bindingResolver The delegate binding resolver.
741              * @return An appropriate binding resolver.
742              */

743             public static BindingResolver toSystemOut(BindingResolver bindingResolver) {
744                 return new StreamWriting(bindingResolver, System.out);
745             }
746
747             /**
748              * Creates a binding resolver that writes results to {@link System#err} and delegates to the {@link Default} resolver.
749              *
750              * @return An appropriate binding resolver.
751              */

752             public static BindingResolver toSystemError() {
753                 return toSystemError(Default.INSTANCE);
754             }
755
756             /**
757              * Creates a binding resolver that writes results to {@link System#err}.
758              *
759              * @param bindingResolver The delegate binding resolver.
760              * @return An appropriate binding resolver.
761              */

762             public static BindingResolver toSystemError(BindingResolver bindingResolver) {
763                 return new StreamWriting(bindingResolver, System.err);
764             }
765
766             /**
767              * {@inheritDoc}
768              */

769             public MethodBinding resolve(AmbiguityResolver ambiguityResolver, MethodDescription source, List<MethodBinding> targets) {
770                 MethodBinding methodBinding = delegate.resolve(ambiguityResolver, source, targets);
771                 printStream.println("Binding " + source + " as delegation to " + methodBinding.getTarget());
772                 return methodBinding;
773             }
774         }
775     }
776
777     /**
778      * Implementations of this interface are able to attempt the resolution of two successful bindings of a method
779      * to two different target methods in order to identify a dominating binding.
780      */

781     @SuppressFBWarnings(value = "IC_SUPERCLASS_USES_SUBCLASS_DURING_INITIALIZATION", justification = "Safe initialization is implied")
782     interface AmbiguityResolver {
783
784         /**
785          * The default ambiguity resolver to use.
786          */

787         AmbiguityResolver DEFAULT = new MethodDelegationBinder.AmbiguityResolver.Compound(BindingPriority.Resolver.INSTANCE,
788                 DeclaringTypeResolver.INSTANCE,
789                 ArgumentTypeResolver.INSTANCE,
790                 MethodNameEqualityResolver.INSTANCE,
791                 ParameterLengthResolver.INSTANCE);
792
793         /**
794          * Attempts to resolve to conflicting bindings.
795          *
796          * @param source The source method that was bound to both target methods.
797          * @param left   The first successful binding of the {@code source} method.
798          * @param right  The second successful binding of the {@code source} method.
799          * @return The resolution state when resolving a conflicting binding where
800          * {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.AmbiguityResolver.Resolution#LEFT}
801          * indicates a successful binding to the {@code left} binding while
802          * {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.AmbiguityResolver.Resolution#RIGHT}
803          * indicates a successful binding to the {@code right} binding.
804          */

805         Resolution resolve(MethodDescription source, MethodBinding left, MethodBinding right);
806
807         /**
808          * A resolution state of an attempt to resolve two conflicting bindings.
809          */

810         enum Resolution {
811
812             /**
813              * Describes a resolution state where no information about dominance could be gathered.
814              */

815             UNKNOWN(true),
816
817             /**
818              * Describes a resolution state where the left method dominates the right method.
819              */

820             LEFT(false),
821
822             /**
823              * Describes a resolution state where the right method dominates the left method.
824              */

825             RIGHT(false),
826
827             /**
828              * Describes a resolution state where both methods have inflicting dominance over each other.
829              */

830             AMBIGUOUS(true);
831
832             /**
833              * {@code trueif this resolution is unresolved.
834              */

835             private final boolean unresolved;
836
837             /**
838              * Creates a new resolution.
839              *
840              * @param unresolved {@code trueif this resolution is unresolved.
841              */

842             Resolution(boolean unresolved) {
843                 this.unresolved = unresolved;
844             }
845
846             /**
847              * Checks if this binding is unresolved.
848              *
849              * @return {@code trueif this binding is unresolved.
850              */

851             public boolean isUnresolved() {
852                 return unresolved;
853             }
854
855             /**
856              * Merges two resolutions in order to determine their compatibility.
857              *
858              * @param other The resolution this resolution is to be checked against.
859              * @return The merged resolution.
860              */

861             public Resolution merge(Resolution other) {
862                 switch (this) {
863                     case UNKNOWN:
864                         return other;
865                     case AMBIGUOUS:
866                         return AMBIGUOUS;
867                     case LEFT:
868                     case RIGHT:
869                         return other == UNKNOWN || other == this
870                                 ? this
871                                 : AMBIGUOUS;
872                     default:
873                         throw new AssertionError();
874                 }
875             }
876         }
877
878         /**
879          * An ambiguity resolver that does not attempt to resolve a conflicting binding.
880          */

881         enum NoOp implements AmbiguityResolver {
882
883             /**
884              * The singleton instance.
885              */

886             INSTANCE;
887
888             /**
889              * {@inheritDoc}
890              */

891             public Resolution resolve(MethodDescription source, MethodBinding left, MethodBinding right) {
892                 return Resolution.UNKNOWN;
893             }
894         }
895
896         /**
897          * An ambiguity resolver that always resolves in the specified direction.
898          */

899         enum Directional implements AmbiguityResolver {
900
901             /**
902              * A resolver that always resolves to
903              * {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.AmbiguityResolver.Resolution#LEFT}.
904              */

905             LEFT(true),
906
907             /**
908              * A resolver that always resolves to
909              * {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.AmbiguityResolver.Resolution#RIGHT}.
910              */

911             RIGHT(false);
912
913             /**
914              * {@code trueif this instance should resolve to the left side.
915              */

916             private final boolean left;
917
918             /**
919              * Creates a new directional resolver.
920              *
921              * @param left {@code trueif this instance should resolve to the left side.
922              */

923             Directional(boolean left) {
924                 this.left = left;
925             }
926
927             /**
928              * {@inheritDoc}
929              */

930             public Resolution resolve(MethodDescription source, MethodBinding left, MethodBinding right) {
931                 return this.left
932                         ? Resolution.LEFT
933                         : Resolution.RIGHT;
934             }
935         }
936
937         /**
938          * A chain of {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.AmbiguityResolver}s
939          * that are applied in the given order until two bindings can be resolved.
940          */

941         @HashCodeAndEqualsPlugin.Enhance
942         class Compound implements AmbiguityResolver {
943
944             /**
945              * A list of ambiguity resolvers that are applied by this chain in their order of application.
946              */

947             private final List<AmbiguityResolver> ambiguityResolvers;
948
949             /**
950              * Creates an immutable chain of ambiguity resolvers.
951              *
952              * @param ambiguityResolver The ambiguity resolvers to chain in the order of their application.
953              */

954             public Compound(AmbiguityResolver... ambiguityResolver) {
955                 this(Arrays.asList(ambiguityResolver));
956             }
957
958             /**
959              * Creates an immutable chain of ambiguity resolvers.
960              *
961              * @param ambiguityResolvers The ambiguity resolvers to chain in the order of their application.
962              */

963             public Compound(List<? extends AmbiguityResolver> ambiguityResolvers) {
964                 this.ambiguityResolvers = new ArrayList<AmbiguityResolver>();
965                 for (AmbiguityResolver ambiguityResolver : ambiguityResolvers) {
966                     if (ambiguityResolver instanceof Compound) {
967                         this.ambiguityResolvers.addAll(((Compound) ambiguityResolver).ambiguityResolvers);
968                     } else if (!(ambiguityResolver instanceof NoOp)) {
969                         this.ambiguityResolvers.add(ambiguityResolver);
970                     }
971                 }
972             }
973
974             /**
975              * {@inheritDoc}
976              */

977             public Resolution resolve(MethodDescription source, MethodBinding left, MethodBinding right) {
978                 Resolution resolution = Resolution.UNKNOWN;
979                 Iterator<? extends AmbiguityResolver> iterator = ambiguityResolvers.iterator();
980                 while (resolution.isUnresolved() && iterator.hasNext()) {
981                     resolution = iterator.next().resolve(source, left, right);
982                 }
983                 return resolution;
984             }
985         }
986     }
987
988     /**
989      * A termination handler is responsible for terminating a method delegation.
990      */

991     interface TerminationHandler {
992
993         /**
994          * Creates a stack manipulation that is to be applied after the method return.
995          *
996          * @param assigner The supplied assigner.
997          * @param typing   The typing to apply.
998          * @param source   The source method that is bound to the {@code target} method.
999          * @param target   The target method that is subject to be bound by the {@code source} method.
1000          * @return A stack manipulation that is applied after the method return.
1001          */

1002         StackManipulation resolve(Assigner assigner, Assigner.Typing typing, MethodDescription source, MethodDescription target);
1003
1004         /**
1005          * Responsible for creating a {@link StackManipulation}
1006          * that is applied after the interception method is applied.
1007          */

1008         enum Default implements TerminationHandler {
1009
1010             /**
1011              * A termination handler that returns the delegate method's return value.
1012              */

1013             RETURNING {
1014                 /** {@inheritDoc} */
1015                 public StackManipulation resolve(Assigner assigner, Assigner.Typing typing, MethodDescription source, MethodDescription target) {
1016                     return new StackManipulation.Compound(assigner.assign(target.isConstructor()
1017                                     ? target.getDeclaringType().asGenericType()
1018                                     : target.getReturnType(),
1019                             source.getReturnType(),
1020                             typing), MethodReturn.of(source.getReturnType()));
1021                 }
1022             },
1023
1024             /**
1025              * A termination handler that drops the delegate method's return value.
1026              */

1027             DROPPING {
1028                 /** {@inheritDoc} */
1029                 public StackManipulation resolve(Assigner assigner, Assigner.Typing typing, MethodDescription source, MethodDescription target) {
1030                     return Removal.of(target.isConstructor()
1031                             ? target.getDeclaringType()
1032                             : target.getReturnType());
1033                 }
1034             };
1035         }
1036     }
1037
1038     /**
1039      * A helper class that allows to identify a best binding for a given type and source method choosing from a list of given
1040      * target methods by using a given {@link net.bytebuddy.implementation.bind.MethodDelegationBinder}
1041      * and an {@link net.bytebuddy.implementation.bind.MethodDelegationBinder.AmbiguityResolver}.
1042      * <p>&nbsp;</p>
1043      * The {@code Processor} will:
1044      * <ol>
1045      * <li>Try to bind the {@code source} method using the {@code MethodDelegationBinder}.</li>
1046      * <li>Find a best method among the successful bindings using the {@code AmbiguityResolver}.</li>
1047      * </ol>
1048      */

1049     @HashCodeAndEqualsPlugin.Enhance
1050     class Processor implements MethodDelegationBinder.Record {
1051
1052         /**
1053          * The delegation records to consider.
1054          */

1055         private final List<? extends Record> records;
1056
1057         /**
1058          * The processor's ambiguity resolver.
1059          */

1060         private final AmbiguityResolver ambiguityResolver;
1061
1062         /**
1063          * The binding resolver being used to select the relevant method binding.
1064          */

1065         private final BindingResolver bindingResolver;
1066
1067         /**
1068          * Creates a new processor.
1069          *
1070          * @param records           The delegation records to consider.
1071          * @param ambiguityResolver The ambiguity resolver to apply.
1072          * @param bindingResolver   The binding resolver being used to select the relevant method binding.
1073          */

1074         public Processor(List<? extends Record> records, AmbiguityResolver ambiguityResolver, BindingResolver bindingResolver) {
1075             this.records = records;
1076             this.ambiguityResolver = ambiguityResolver;
1077             this.bindingResolver = bindingResolver;
1078         }
1079
1080         /**
1081          * {@inheritDoc}
1082          */

1083         public MethodBinding bind(Implementation.Target implementationTarget,
1084                                   MethodDescription source,
1085                                   TerminationHandler terminationHandler,
1086                                   MethodInvoker methodInvoker,
1087                                   Assigner assigner) {
1088             List<MethodBinding> targets = new ArrayList<MethodBinding>();
1089             for (Record record : records) {
1090                 MethodBinding methodBinding = record.bind(implementationTarget, source, terminationHandler, methodInvoker, assigner);
1091                 if (methodBinding.isValid()) {
1092                     targets.add(methodBinding);
1093                 }
1094             }
1095             if (targets.isEmpty()) {
1096                 throw new IllegalArgumentException("None of " + records + " allows for delegation from " + source);
1097             }
1098             return bindingResolver.resolve(ambiguityResolver, source, targets);
1099         }
1100     }
1101 }
1102