// Generated by delombok at Sun Feb 26 12:31:38 KST 2017
package scouter.bytebuddy.implementation;
import scouter.bytebuddy.description.field.FieldDescription;
import scouter.bytebuddy.description.method.MethodDescription;
import scouter.bytebuddy.description.method.MethodList;
import scouter.bytebuddy.description.type.TypeDefinition;
import scouter.bytebuddy.description.type.TypeDescription;
import scouter.bytebuddy.dynamic.scaffold.FieldLocator;
import scouter.bytebuddy.dynamic.scaffold.InstrumentedType;
import scouter.bytebuddy.dynamic.scaffold.MethodGraph;
import scouter.bytebuddy.implementation.bind.*;
import scouter.bytebuddy.implementation.bind.annotation.TargetMethodAnnotationDrivenBinder;
import scouter.bytebuddy.implementation.bytecode.ByteCodeAppender;
import scouter.bytebuddy.implementation.bytecode.Duplication;
import scouter.bytebuddy.implementation.bytecode.StackManipulation;
import scouter.bytebuddy.implementation.bytecode.TypeCreation;
import scouter.bytebuddy.implementation.bytecode.assign.Assigner;
import scouter.bytebuddy.implementation.bind.annotation.*;
import scouter.bytebuddy.implementation.bytecode.member.FieldAccess;
import scouter.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
import scouter.bytebuddy.matcher.ElementMatcher;
import scouter.bytebuddy.utility.CompoundList;
import scouter.bytebuddy.utility.RandomString;
import scouter.bytebuddy.jar.asm.MethodVisitor;
import scouter.bytebuddy.jar.asm.Opcodes;
import scouter.bytebuddy.matcher.ElementMatchers;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static scouter.bytebuddy.matcher.ElementMatchers.*;
/**
* This implementation delegates an method call to another method which can either be {@code static} by providing
* a reference to a {@link java.lang.Class} or an instance method when another object is provided. The potential
* targets of the method delegation can further be filtered by applying a filter. The method delegation can be
* customized by invoking the {@code MethodDelegation}'s several builder methods.
* <h3>Without any customization, the method delegation will work as follows:</h3>
* <span style="text-decoration: underline">Binding an instrumented method to a given delegate method</span>
* <p> </p>
* A method will be bound parameter by parameter. Considering a method {@code Foo#bar} being bound to a method
* {@code Qux#baz}, the method delegation will be decided on basis of the following annotations:
* <ul>
* <li>{@link Argument}:
* This annotation will bind the {@code n}-th parameter of {@code Foo#bar} to that parameter of {@code Qux#baz}that
* is annotated with this annotation where {@code n} is the obligatory argument of the {@code @Argument} annotation.</li>
* <li>{@link AllArguments}:
* This annotation will assign a collection of all parameters of {@code Foo#bar} to that parameter of {@code Qux#baz}
* that is annotated with {@code AllArguments}.</li>
* <li>{@link This}: A parameter
* of {@code Qux#baz} that is annotated with {@code This} will be assigned the instance that is instrumented for
* a non-static method.</li>
* <li>{@link Super}: A parameter that is annotated with
* this annotation is assigned a proxy that allows calling an instrumented type's super methods.</li>
* <li>{@link Default}: A parameter that is annotated with
* this annotation is assigned a proxy that allows calling an instrumented type's directly implemented interfaces'
* default methods.</li>
* <li>{@link SuperCall}: A parameter
* of {@code Qux#baz} that is annotated with {@code SuperCall} will be assigned an instance of a type implementing both
* {@link java.lang.Runnable} and {@link java.util.concurrent.Callable} which will invoke the instrumented method on the
* invocation of either interface's method. The call is made using the original arguments of the method invocation.
* The return value is only emitted for the {@link java.util.concurrent.Callable#call()} method which additionally
* requires to catch any unchecked exceptions that might be thrown by the original method's implementation. If a
* source method is abstract, using this annotation excludes the method with this parameter annotation from being bound
* to this source method.
* </li>
* <li>{@link DefaultCall}:
* This annotation is similar to the {@link SuperCall}
* annotation but it invokes a default method that is compatible to this method. If a source method does not represent
* a default method, using this annotation excludes the method with this parameter annotation from being bound to this
* source method.</li>
* <li>The {@link SuperMethod} or
* {@link DefaultMethod} annotations can be used on any parameter type
* that is assignable from the {@link java.lang.reflect.Method} type. the parameter is bound a method instance that
* allows for the reflective invocation of a super or default method. Note that this method is not equal to the intercepted
* method but represents a synthetic accessor method. Using this annotation also causes this accessor to be {@code public}
* which allows its outside invocation without any access checks by a security manager.</li>
* <li>{@link Origin}: A parameter of
* {@code Qux#baz} that is annotated with {@code Origin} is assigned a reference to either a {@link java.lang.reflect.Method},
* a {@link java.lang.reflect.Constructor}, a {@code java.lang.reflect.Executable} or a {@link java.lang.Class} instance.
* A {@code Method}-typed, {@code Constructor} or {@code Executable} parameter is assigned a reference to the original
* method that is instrumented. A {@code Class}-typed parameter is assigned the type of the caller. Furthermore, {@code MethodType}
* and {@code MethodHandle} parameters are also supported. When using the annotation on a {@link java.lang.String} type,
* the intercepted method's {@code toString} value is injected. The same holds for a parameter of type {@code int} that receives
* the modifiers of the instrumented method.</li>
* <li>{@link StubValue}: Assigns the (boxed) default value of the
* intercepted method's return type to the parameter. If the return type is {@code void}, {@code null} is assigned.</li>
* <li>{@link Empty}: Assigns the parameter type's
* default value, i.e. {@code null} for a reference type or zero for primitive types. This is an opportunity to
* ignore a parameter.</li>
* <li>{@link Pipe}: A parameter that is annotated
* with this annotation is assigned a proxy for forwarding the source method invocation to another instance of the
* same type as the declaring type of the intercepted method. <b>This annotation needs to be installed and explicitly
* registered before it can be used.</b> See the {@link Pipe}
* annotation's documentation for further information on how this can be done.</li>
* <li>{@link Morph}: The morph annotation is similar to
* the {@link SuperCall} annotation but allows to
* explicitly define and therewith alter the arguments that are handed to the super method. <b>This annotation needs
* to be installed and explicitly registered before it can be used.</b> See the documentation to the annotation for
* further information.</li>
* <li>{@link FieldValue}: Allows to access a field's value at the time
* of the method invocation. The field's value is directly assigned to the annotated parameter.</li>
* <li>{@link FieldProxy}: Allows to access fields via getter
* and setter proxies. <b>This annotation needs to be installed and explicitly registered before it can be used.</b>
* Note that any field access requires boxing such that a use of {@link FieldAccessor} in
* combination with {@link MethodDelegation#andThen(Implementation)} might be a more
* performant alternative for implementing field getters and setters.</li>
* </ul>
* If a method is not annotated with any of the above methods, it will be treated as if it was annotated
* {@link Argument} using the next
* unbound parameter index of the source method as its parameter. This means that a method
* {@code Qux#baz(@Argument(2) Object p1, Object p2, @Argument(0) Object p3} would be treated as if {@code p2} was annotated
* with {@code @Argument(1)}.
* <p> </p>
* In addition, the {@link RuntimeType}
* annotation can instruct a parameter to be bound by a
* {@link Assigner} with considering the
* runtime type of the parameter.
* <p> </p>
* <span style="text-decoration: underline">Selecting among different methods that can be used for binding a method
* of the instrumented type</span>
* <p> </p>
* When deciding between two methods {@code Foo#bar} and {@code Foo#qux} that could both be used to delegating a
* method call, the following consideration is applied in the given order:
* <ol>
* <li>{@link BindingPriority}:
* A method that is annotated with this annotation is given a specific priority where the default priority is set
* to {@link BindingPriority#DEFAULT}
* for non-annotated method. A method with a higher priority is considered a better target for delegation.</li>
* <li>{@link DeclaringTypeResolver}:
* If a target method is declared by a more specific type than another method, the method with the most specific
* type is bound.</li>
* <li>{@link MethodNameEqualityResolver}:
* If a source method {@code Baz#qux} is the source method, it will rather be assigned to {@code Foo#qux} because
* of their equal names. Similar names and case-insensitive equality are not considered.</li>
* <li>{@link ArgumentTypeResolver}:
* The most specific type resolver will consider all bindings that are using the
* {@link Argument}
* annotation for resolving a binding conflict. In this context, the resolution will equal the most-specific
* type resolution that is performed by the Java compiler. This means that a source method {@code Bar#baz(String)}
* will rather be bound to a method {@code Foo#bar(String)} than {@code Foo#qux(Object)} because the {@code String}
* type is more specific than the {@code Object} type. If two methods are equally adequate by their parameter types,
* then the method with the higher numbers of {@code @Argument} annotated parameters is considered as the better
* delegation target.</li>
* <li>{@link ParameterLengthResolver}:
* If a target methods has a higher number of total parameters that were successfully bound, the method with
* the higher number will be considered as the better delegation target.</li>
* </ol>
* <p>
* Additionally, if a method is annotated by
* {@link IgnoreForBinding},
* it is never considered as a target for a method delegation.
* </p>
* <p>
* <b>Important</b>: For invoking a method on another instance, use the {@link MethodCall} implementation. A method delegation
* intends to bind a interceptor class and its resolution algorithm will not necessarily yield a delegation to the intercepted
* method.
* </p>
*
* @see MethodCall
* @see TargetMethodAnnotationDrivenBinder.ParameterBinder.ForFixedValue
*/
public class MethodDelegation implements Implementation.Composable {
/**
* The implementation delegate for this method delegation.
*/
private final ImplementationDelegate implementationDelegate;
/**
* A list of {@link TargetMethodAnnotationDrivenBinder.ParameterBinder}s
* to be used by this method delegation.
*/
private final List<TargetMethodAnnotationDrivenBinder.ParameterBinder<?>> parameterBinders;
/**
* The {@link MethodDelegationBinder.AmbiguityResolver}
* to be used by this method delegation.
*/
private final MethodDelegationBinder.AmbiguityResolver ambiguityResolver;
/**
* The termination handler to apply.
*/
private final TargetMethodAnnotationDrivenBinder.TerminationHandler terminationHandler;
/**
* The {@link Assigner} to be used by this method delegation.
*/
private final Assigner assigner;
/**
* Creates a new method delegation.
*
* @param implementationDelegate The implementation delegate to use by this method delegator.
* @param parameterBinders The parameter binders to use by this method delegator.
* @param ambiguityResolver The ambiguity resolver to use by this method delegator.
*/
protected MethodDelegation(ImplementationDelegate implementationDelegate, List<TargetMethodAnnotationDrivenBinder.ParameterBinder<?>> parameterBinders, MethodDelegationBinder.AmbiguityResolver ambiguityResolver) {
this(implementationDelegate, parameterBinders, ambiguityResolver, MethodDelegationBinder.TerminationHandler.Default.RETURNING, Assigner.DEFAULT);
}
/**
* Creates a new method delegation.
*
* @param implementationDelegate The implementation delegate to use by this method delegator.
* @param parameterBinders The parameter binders to use by this method delegator.
* @param ambiguityResolver The ambiguity resolver to use by this method delegator.
* @param terminationHandler The termination handler to apply.
* @param assigner The assigner to be supplied by this method delegator.
*/
private MethodDelegation(ImplementationDelegate implementationDelegate, List<TargetMethodAnnotationDrivenBinder.ParameterBinder<?>> parameterBinders, MethodDelegationBinder.AmbiguityResolver ambiguityResolver, TargetMethodAnnotationDrivenBinder.TerminationHandler terminationHandler, Assigner assigner) {
this.implementationDelegate = implementationDelegate;
this.parameterBinders = parameterBinders;
this.terminationHandler = terminationHandler;
this.ambiguityResolver = ambiguityResolver;
this.assigner = assigner;
}
/**
* Delegates any intercepted method to invoke a {@code static} method that is declared by the supplied type. To be considered
* a valid delegation target, the target method must be visible and accessible to the instrumented type. This is the case if
* the target type is either public or in the same package as the instrumented type and if the target method is either public
* or non-private and in the same package as the instrumented type. Private methods can only be used as a delegation target if
* the interception is targeting the instrumented type.
*
* @param type The target type for the delegation.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public static MethodDelegation to(Class<?> type) {
return withDefaultConfiguration().to(type);
}
/**
* Delegates any intercepted method to invoke a {@code static} method that is declared by the supplied type. To be considered
* a valid delegation target, the target method must be visible and accessible to the instrumented type. This is the case if
* the target type is either public or in the same package as the instrumented type and if the target method is either public
* or non-private and in the same package as the instrumented type. Private methods can only be used as a delegation target if
* the interception is targeting the instrumented type.
*
* @param typeDescription The target type for the delegation.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public static MethodDelegation to(TypeDescription typeDescription) {
return withDefaultConfiguration().to(typeDescription);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public static MethodDelegation to(Object target) {
return withDefaultConfiguration().to(target);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param methodGraphCompiler The method graph compiler to use.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public static MethodDelegation to(Object target, MethodGraph.Compiler methodGraphCompiler) {
return withDefaultConfiguration().to(target, methodGraphCompiler);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param fieldName The name of the field that is holding the {@code target} instance.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public static MethodDelegation to(Object target, String fieldName) {
return withDefaultConfiguration().to(target, fieldName);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param fieldName The name of the field that is holding the {@code target} instance.
* @param methodGraphCompiler The method graph compiler to use.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public static MethodDelegation to(Object target, String fieldName, MethodGraph.Compiler methodGraphCompiler) {
return withDefaultConfiguration().to(target, fieldName, methodGraphCompiler);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param type The most specific type of which {@code target} should be cosnidered. Must be a super type of the target's actual type.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public static MethodDelegation to(Object target, Type type) {
return withDefaultConfiguration().to(target, type);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param type The most specific type of which {@code target} should be cosnidered. Must be a super type of the target's actual type.
* @param methodGraphCompiler The method graph compiler to use.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public static MethodDelegation to(Object target, Type type, MethodGraph.Compiler methodGraphCompiler) {
return withDefaultConfiguration().to(target, type, methodGraphCompiler);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param type The most specific type of which {@code target} should be cosnidered. Must be a super type of the target's actual type.
* @param fieldName The name of the field that is holding the {@code target} instance.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public static MethodDelegation to(Object target, Type type, String fieldName) {
return withDefaultConfiguration().to(target, type, fieldName);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param type The most specific type of which {@code target} should be cosnidered. Must be a super type of the target's actual type.
* @param fieldName The name of the field that is holding the {@code target} instance.
* @param methodGraphCompiler The method graph compiler to use.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public static MethodDelegation to(Object target, Type type, String fieldName, MethodGraph.Compiler methodGraphCompiler) {
return withDefaultConfiguration().to(target, type, fieldName, methodGraphCompiler);
}
/**
* Delegates any intercepted method to invoke a constructor of the supplied type. To be considered a valid delegation target,
* a constructor must be visible and accessible to the instrumented type. This is the case if the constructor's declaring type is
* either public or in the same package as the instrumented type and if the constructor is either public or non-private and in
* the same package as the instrumented type. Private constructors can only be used as a delegation target if the delegation is
* targeting the instrumented type.
*
* @param type The type to construct.
* @return A delegation that redirects method calls to a constructor of the supplied type.
*/
public static MethodDelegation toConstructor(Class<?> type) {
return withDefaultConfiguration().toConstructor(type);
}
/**
* Delegates any intercepted method to invoke a constructor of the supplied type. To be considered a valid delegation target,
* a constructor must be visible and accessible to the instrumented type. This is the case if the constructor's declaring type is
* either public or in the same package as the instrumented type and if the constructor is either public or non-private and in
* the same package as the instrumented type. Private constructors can only be used as a delegation target if the delegation is
* targeting the instrumented type.
*
* @param typeDescription The type to construct.
* @return A delegation that redirects method calls to a constructor of the supplied type.
*/
public static MethodDelegation toConstructor(TypeDescription typeDescription) {
return withDefaultConfiguration().toConstructor(typeDescription);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method on the instance of the supplied field. To be
* considered a valid delegation target, a method must be visible and accessible to the instrumented type. This is the
* case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the ddelegation is targeting the instrumented type.
*
* @param name The field's name.
* @return A delegation that redirects invocations to a method of the specified field's instance.
*/
public static MethodDelegation toField(String name) {
return withDefaultConfiguration().toField(name);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method on the instance of the supplied field. To be
* considered a valid delegation target, a method must be visible and accessible to the instrumented type. This is the
* case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the ddelegation is targeting the instrumented type.
*
* @param name The field's name.
* @param fieldLocatorFactory The field locator factory to use.
* @return A delegation that redirects invocations to a method of the specified field's instance.
*/
public static MethodDelegation toField(String name, FieldLocator.Factory fieldLocatorFactory) {
return withDefaultConfiguration().toField(name, fieldLocatorFactory);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method on the instance of the supplied field. To be
* considered a valid delegation target, a method must be visible and accessible to the instrumented type. This is the
* case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the ddelegation is targeting the instrumented type.
*
* @param name The field's name.
* @param methodGraphCompiler The method graph compiler to use.
* @return A delegation that redirects invocations to a method of the specified field's instance.
*/
public static MethodDelegation toField(String name, MethodGraph.Compiler methodGraphCompiler) {
return withDefaultConfiguration().toField(name, methodGraphCompiler);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method on the instance of the supplied field. To be
* considered a valid delegation target, a method must be visible and accessible to the instrumented type. This is the
* case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the ddelegation is targeting the instrumented type.
*
* @param name The field's name.
* @param fieldLocatorFactory The field locator factory to use.
* @param methodGraphCompiler The method graph compiler to use.
* @return A delegation that redirects invocations to a method of the specified field's instance.
*/
public static MethodDelegation toField(String name, FieldLocator.Factory fieldLocatorFactory, MethodGraph.Compiler methodGraphCompiler) {
return withDefaultConfiguration().toField(name, fieldLocatorFactory, methodGraphCompiler);
}
/**
* Creates a configuration builder for a method delegation that is pre-configured with the ambiguity resolvers defined by
* {@link MethodDelegationBinder.AmbiguityResolver#DEFAULT} and the parameter binders
* defined by {@link TargetMethodAnnotationDrivenBinder.ParameterBinder#DEFAULTS}.
*
* @return A method delegation configuration with pre-configuration.
*/
public static WithCustomProperties withDefaultConfiguration() {
return new WithCustomProperties(MethodDelegationBinder.AmbiguityResolver.DEFAULT, TargetMethodAnnotationDrivenBinder.ParameterBinder.DEFAULTS);
}
/**
* Creates a configuration builder for a method delegation that does not apply any pre-configured
* {@link MethodDelegationBinder.AmbiguityResolver}s or
* {@link TargetMethodAnnotationDrivenBinder.ParameterBinder}s.
*
* @return A method delegation configuration without any pre-configuration.
*/
public static WithCustomProperties withEmptyConfiguration() {
return new WithCustomProperties(MethodDelegationBinder.AmbiguityResolver.NoOp.INSTANCE, Collections.<TargetMethodAnnotationDrivenBinder.ParameterBinder<?>>emptyList());
}
/**
* Applies an assigner to the method delegation that is used for assigning method return and parameter types.
*
* @param assigner The assigner to apply.
* @return A method delegation implementation that makes use of the given designer.
*/
public Implementation.Composable withAssigner(Assigner assigner) {
return new MethodDelegation(implementationDelegate, parameterBinders, ambiguityResolver, terminationHandler, assigner);
}
@Override
public Implementation andThen(Implementation implementation) {
return new Compound(new MethodDelegation(implementationDelegate, parameterBinders, ambiguityResolver, MethodDelegationBinder.TerminationHandler.Default.DROPPING, assigner), implementation);
}
@Override
public InstrumentedType prepare(InstrumentedType instrumentedType) {
return implementationDelegate.prepare(instrumentedType);
}
@Override
public ByteCodeAppender appender(Target implementationTarget) {
ImplementationDelegate.Compiled compiled = implementationDelegate.compile(implementationTarget.getInstrumentedType());
return new Appender(implementationTarget, new MethodDelegationBinder.Processor(compiled.getRecords(), ambiguityResolver), terminationHandler, assigner, compiled);
}
/**
* An implementation delegate is responsible for executing the actual method delegation and for resolving the target methods.
*/
protected interface ImplementationDelegate extends InstrumentedType.Prepareable {
/**
* A name prefix for fields.
*/
String FIELD_NAME_PREFIX = "delegate";
/**
* Compiles this implementation delegate.
*
* @param instrumentedType The instrumented type.
* @return A compiled implementation delegate.
*/
Compiled compile(TypeDescription instrumentedType);
/**
* A compiled implementation delegate.
*/
interface Compiled {
/**
* Resolves a stack manipulation that prepares the delegation invocation.
*
* @param instrumentedMethod The instrumented method.
* @return A stack manipulation that is applied prior to loading arguments and executing the method call.
*/
StackManipulation prepare(MethodDescription instrumentedMethod);
/**
* Resolves an invoker to use for invoking the delegation target.
*
* @return The method invoker to use.
*/
MethodDelegationBinder.MethodInvoker invoke();
/**
* Returns a list of binding records to consider for delegation.
*
* @return A list of delegation binder records to consider.
*/
List<MethodDelegationBinder.Record> getRecords();
/**
* A compiled implementation delegate for invoking a static method.
*/
class ForStaticCall implements Compiled {
/**
* The list of records to consider.
*/
private final List<MethodDelegationBinder.Record> records;
/**
* Creates a new compiled implementation delegate for a static method call.
*
* @param records The list of records to consider.
*/
protected ForStaticCall(List<MethodDelegationBinder.Record> records) {
this.records = records;
}
@Override
public StackManipulation prepare(MethodDescription instrumentedMethod) {
return StackManipulation.Trivial.INSTANCE;
}
@Override
public MethodDelegationBinder.MethodInvoker invoke() {
return MethodDelegationBinder.MethodInvoker.Simple.INSTANCE;
}
@Override
public List<MethodDelegationBinder.Record> getRecords() {
return records;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof MethodDelegation.ImplementationDelegate.Compiled.ForStaticCall)) return false;
final MethodDelegation.ImplementationDelegate.Compiled.ForStaticCall other = (MethodDelegation.ImplementationDelegate.Compiled.ForStaticCall) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$records = this.getRecords();
final java.lang.Object other$records = other.getRecords();
if (this$records == null ? other$records != null : !this$records.equals(other$records)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof MethodDelegation.ImplementationDelegate.Compiled.ForStaticCall;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $records = this.getRecords();
result = result * PRIME + ($records == null ? 43 : $records.hashCode());
return result;
}
}
/**
* A compiled implementation delegate that invokes methods on a field.
*/
class ForField implements Compiled {
/**
* The field to delegate to.
*/
private final FieldDescription fieldDescription;
/**
* The records to consider for delegation.
*/
private final List<MethodDelegationBinder.Record> records;
/**
* Creates a new compiled implementation delegate for a field delegation.
*
* @param fieldDescription The field to delegate to.
* @param records The records to consider for delegation.
*/
protected ForField(FieldDescription fieldDescription, List<MethodDelegationBinder.Record> records) {
this.fieldDescription = fieldDescription;
this.records = records;
}
@Override
public StackManipulation prepare(MethodDescription instrumentedMethod) {
if (instrumentedMethod.isStatic() && !fieldDescription.isStatic()) {
throw new IllegalStateException("Cannot read " + fieldDescription + " from " + instrumentedMethod);
}
return new StackManipulation.Compound(fieldDescription.isStatic() ? StackManipulation.Trivial.INSTANCE : MethodVariableAccess.loadThis(), FieldAccess.forField(fieldDescription).read());
}
@Override
public MethodDelegationBinder.MethodInvoker invoke() {
return new MethodDelegationBinder.MethodInvoker.Virtual(fieldDescription.getType().asErasure());
}
@Override
public List<MethodDelegationBinder.Record> getRecords() {
return records;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof MethodDelegation.ImplementationDelegate.Compiled.ForField)) return false;
final MethodDelegation.ImplementationDelegate.Compiled.ForField other = (MethodDelegation.ImplementationDelegate.Compiled.ForField) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$fieldDescription = this.fieldDescription;
final java.lang.Object other$fieldDescription = other.fieldDescription;
if (this$fieldDescription == null ? other$fieldDescription != null : !this$fieldDescription.equals(other$fieldDescription)) return false;
final java.lang.Object this$records = this.getRecords();
final java.lang.Object other$records = other.getRecords();
if (this$records == null ? other$records != null : !this$records.equals(other$records)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof MethodDelegation.ImplementationDelegate.Compiled.ForField;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $fieldDescription = this.fieldDescription;
result = result * PRIME + ($fieldDescription == null ? 43 : $fieldDescription.hashCode());
final java.lang.Object $records = this.getRecords();
result = result * PRIME + ($records == null ? 43 : $records.hashCode());
return result;
}
}
/**
* A compiled implementation delegate for a constructor delegation.
*/
class ForConstruction implements Compiled {
/**
* The type to be constructed.
*/
private final TypeDescription typeDescription;
/**
* The records to consider for delegation.
*/
private final List<MethodDelegationBinder.Record> records;
/**
* Creates a new compiled implementation delegate for a constructor delegation.
*
* @param typeDescription The type to be constructed.
* @param records The records to consider for delegation.
*/
protected ForConstruction(TypeDescription typeDescription, List<MethodDelegationBinder.Record> records) {
this.typeDescription = typeDescription;
this.records = records;
}
@Override
public StackManipulation prepare(MethodDescription instrumentedMethod) {
return new StackManipulation.Compound(TypeCreation.of(typeDescription), Duplication.SINGLE);
}
@Override
public MethodDelegationBinder.MethodInvoker invoke() {
return MethodDelegationBinder.MethodInvoker.Simple.INSTANCE;
}
@Override
public List<MethodDelegationBinder.Record> getRecords() {
return records;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof MethodDelegation.ImplementationDelegate.Compiled.ForConstruction)) return false;
final MethodDelegation.ImplementationDelegate.Compiled.ForConstruction other = (MethodDelegation.ImplementationDelegate.Compiled.ForConstruction) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$typeDescription = this.typeDescription;
final java.lang.Object other$typeDescription = other.typeDescription;
if (this$typeDescription == null ? other$typeDescription != null : !this$typeDescription.equals(other$typeDescription)) return false;
final java.lang.Object this$records = this.getRecords();
final java.lang.Object other$records = other.getRecords();
if (this$records == null ? other$records != null : !this$records.equals(other$records)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof MethodDelegation.ImplementationDelegate.Compiled.ForConstruction;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $typeDescription = this.typeDescription;
result = result * PRIME + ($typeDescription == null ? 43 : $typeDescription.hashCode());
final java.lang.Object $records = this.getRecords();
result = result * PRIME + ($records == null ? 43 : $records.hashCode());
return result;
}
}
}
/**
* An implementation delegate for a static method delegation.
*/
class ForStaticMethod implements ImplementationDelegate {
/**
* The precompiled records.
*/
private final List<MethodDelegationBinder.Record> records;
/**
* Creates a new implementation delegate for a static method delegation.
*
* @param records The precompiled record.
*/
protected ForStaticMethod(List<MethodDelegationBinder.Record> records) {
this.records = records;
}
/**
* Precompiles a static method delegation for a given list of methods.
*
* @param methods The methods to consider.
* @param methodDelegationBinder The method delegation binder to use.
* @return An appropriate implementation delegate.
*/
protected static ImplementationDelegate of(MethodList<?> methods, MethodDelegationBinder methodDelegationBinder) {
List<MethodDelegationBinder.Record> records = new ArrayList<MethodDelegationBinder.Record>(methods.size());
for (MethodDescription methodDescription : methods) {
records.add(methodDelegationBinder.compile(methodDescription));
}
return new ForStaticMethod(records);
}
@Override
public InstrumentedType prepare(InstrumentedType instrumentedType) {
return instrumentedType;
}
@Override
public ImplementationDelegate.Compiled compile(TypeDescription instrumentedType) {
return new Compiled.ForStaticCall(records);
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof MethodDelegation.ImplementationDelegate.ForStaticMethod)) return false;
final MethodDelegation.ImplementationDelegate.ForStaticMethod other = (MethodDelegation.ImplementationDelegate.ForStaticMethod) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$records = this.records;
final java.lang.Object other$records = other.records;
if (this$records == null ? other$records != null : !this$records.equals(other$records)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof MethodDelegation.ImplementationDelegate.ForStaticMethod;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $records = this.records;
result = result * PRIME + ($records == null ? 43 : $records.hashCode());
return result;
}
}
/**
* An implementation delegate for invoking methods on a field that is declared by the instrumented type or a super type.
*/
abstract class ForField implements ImplementationDelegate {
/**
* The name of the field that is target of the delegation.
*/
protected final String fieldName;
/**
* The method graph compiler to use.
*/
protected final MethodGraph.Compiler methodGraphCompiler;
/**
* The parameter binders to use.
*/
protected final List<? extends TargetMethodAnnotationDrivenBinder.ParameterBinder<?>> parameterBinders;
/**
* The matcher to use for filtering methods.
*/
protected final ElementMatcher<? super MethodDescription> matcher;
/**
* Creates a new implementation delegate for a field delegation.
*
* @param fieldName The name of the field that is target of the delegation.
* @param methodGraphCompiler The method graph compiler to use.
* @param parameterBinders The parameter binders to use.
* @param matcher The matcher to use for filtering methods.
*/
protected ForField(String fieldName, MethodGraph.Compiler methodGraphCompiler, List<? extends TargetMethodAnnotationDrivenBinder.ParameterBinder<?>> parameterBinders, ElementMatcher<? super MethodDescription> matcher) {
this.fieldName = fieldName;
this.methodGraphCompiler = methodGraphCompiler;
this.parameterBinders = parameterBinders;
this.matcher = matcher;
}
@Override
public Compiled compile(TypeDescription instrumentedType) {
FieldDescription fieldDescription = resolve(instrumentedType);
if (!fieldDescription.getType().asErasure().isVisibleTo(instrumentedType)) {
throw new IllegalStateException(fieldDescription + " is not visible to " + instrumentedType);
} else {
MethodList<?> candidates = methodGraphCompiler.compile(fieldDescription.getType(), instrumentedType).listNodes().asMethodList().filter(matcher);
List<MethodDelegationBinder.Record> records = new ArrayList<MethodDelegationBinder.Record>(candidates.size());
MethodDelegationBinder methodDelegationBinder = TargetMethodAnnotationDrivenBinder.of(parameterBinders);
for (MethodDescription candidate : candidates) {
records.add(methodDelegationBinder.compile(candidate));
}
return new Compiled.ForField(fieldDescription, records);
}
}
/**
* Resolves the field to which is delegated.
*
* @param instrumentedType The instrumented type.
* @return The field that is the delegation target.
*/
protected abstract FieldDescription resolve(TypeDescription instrumentedType);
/**
* An implementation target for a static field that is declared by the instrumented type and that is assigned an instance.
*/
protected static class WithInstance extends ForField {
/**
* The target instance.
*/
private final Object target;
/**
* The field's type.
*/
private final TypeDescription.Generic fieldType;
/**
* Creates a new implementation delegate for invoking methods on a supplied instance.
*
* @param fieldName The name of the field that is target of the delegation.
* @param methodGraphCompiler The method graph compiler to use.
* @param parameterBinders The parameter binders to use.
* @param matcher The matcher to use for filtering methods.
* @param target The target instance.
* @param fieldType The field's type.
*/
protected WithInstance(String fieldName, MethodGraph.Compiler methodGraphCompiler, List<? extends TargetMethodAnnotationDrivenBinder.ParameterBinder<?>> parameterBinders, ElementMatcher<? super MethodDescription> matcher, Object target, TypeDescription.Generic fieldType) {
super(fieldName, methodGraphCompiler, parameterBinders, matcher);
this.target = target;
this.fieldType = fieldType;
}
@Override
public InstrumentedType prepare(InstrumentedType instrumentedType) {
return instrumentedType.withField(new FieldDescription.Token(fieldName, Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, fieldType)).withInitializer(new LoadedTypeInitializer.ForStaticField(fieldName, target));
}
@Override
protected FieldDescription resolve(TypeDescription instrumentedType) {
if (!fieldType.asErasure().isVisibleTo(instrumentedType)) {
throw new IllegalStateException(fieldType + " is not visible to " + instrumentedType);
} else {
return instrumentedType.getDeclaredFields().filter(ElementMatchers.named(fieldName).and(fieldType(fieldType.asErasure()))).getOnly();
}
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof MethodDelegation.ImplementationDelegate.ForField.WithInstance)) return false;
final MethodDelegation.ImplementationDelegate.ForField.WithInstance other = (MethodDelegation.ImplementationDelegate.ForField.WithInstance) o;
if (!other.canEqual((java.lang.Object) this)) return false;
if (!super.equals(o)) return false;
final java.lang.Object this$target = this.target;
final java.lang.Object other$target = other.target;
if (this$target == null ? other$target != null : !this$target.equals(other$target)) return false;
final java.lang.Object this$fieldType = this.fieldType;
final java.lang.Object other$fieldType = other.fieldType;
if (this$fieldType == null ? other$fieldType != null : !this$fieldType.equals(other$fieldType)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof MethodDelegation.ImplementationDelegate.ForField.WithInstance;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + super.hashCode();
final java.lang.Object $target = this.target;
result = result * PRIME + ($target == null ? 43 : $target.hashCode());
final java.lang.Object $fieldType = this.fieldType;
result = result * PRIME + ($fieldType == null ? 43 : $fieldType.hashCode());
return result;
}
}
/**
* An implementation target for a field that is declared by the instrumented type or a super type.
*/
protected static class WithLookup extends ForField {
/**
* The field locator factory to use for locating the field to delegate to.
*/
private final FieldLocator.Factory fieldLocatorFactory;
/**
* Creates a new implementation delegate for a field that is declared by the instrumented type or any super type.
*
* @param fieldName The name of the field that is target of the delegation.
* @param methodGraphCompiler The method graph compiler to use.
* @param parameterBinders The parameter binders to use.
* @param matcher The matcher to use for filtering methods.
* @param fieldLocatorFactory The field locator factory to use for locating the field to delegate to.
*/
protected WithLookup(String fieldName, MethodGraph.Compiler methodGraphCompiler, List<? extends TargetMethodAnnotationDrivenBinder.ParameterBinder<?>> parameterBinders, ElementMatcher<? super MethodDescription> matcher, FieldLocator.Factory fieldLocatorFactory) {
super(fieldName, methodGraphCompiler, parameterBinders, matcher);
this.fieldLocatorFactory = fieldLocatorFactory;
}
@Override
public InstrumentedType prepare(InstrumentedType instrumentedType) {
return instrumentedType;
}
@Override
protected FieldDescription resolve(TypeDescription instrumentedType) {
FieldLocator.Resolution resolution = fieldLocatorFactory.make(instrumentedType).locate(fieldName);
if (!resolution.isResolved()) {
throw new IllegalStateException("Could not locate " + fieldName + " on " + instrumentedType);
} else {
return resolution.getField();
}
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof MethodDelegation.ImplementationDelegate.ForField.WithLookup)) return false;
final MethodDelegation.ImplementationDelegate.ForField.WithLookup other = (MethodDelegation.ImplementationDelegate.ForField.WithLookup) o;
if (!other.canEqual((java.lang.Object) this)) return false;
if (!super.equals(o)) return false;
final java.lang.Object this$fieldLocatorFactory = this.fieldLocatorFactory;
final java.lang.Object other$fieldLocatorFactory = other.fieldLocatorFactory;
if (this$fieldLocatorFactory == null ? other$fieldLocatorFactory != null : !this$fieldLocatorFactory.equals(other$fieldLocatorFactory)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof MethodDelegation.ImplementationDelegate.ForField.WithLookup;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
result = result * PRIME + super.hashCode();
final java.lang.Object $fieldLocatorFactory = this.fieldLocatorFactory;
result = result * PRIME + ($fieldLocatorFactory == null ? 43 : $fieldLocatorFactory.hashCode());
return result;
}
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof MethodDelegation.ImplementationDelegate.ForField)) return false;
final MethodDelegation.ImplementationDelegate.ForField other = (MethodDelegation.ImplementationDelegate.ForField) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$fieldName = this.fieldName;
final java.lang.Object other$fieldName = other.fieldName;
if (this$fieldName == null ? other$fieldName != null : !this$fieldName.equals(other$fieldName)) return false;
final java.lang.Object this$methodGraphCompiler = this.methodGraphCompiler;
final java.lang.Object other$methodGraphCompiler = other.methodGraphCompiler;
if (this$methodGraphCompiler == null ? other$methodGraphCompiler != null : !this$methodGraphCompiler.equals(other$methodGraphCompiler)) return false;
final java.lang.Object this$parameterBinders = this.parameterBinders;
final java.lang.Object other$parameterBinders = other.parameterBinders;
if (this$parameterBinders == null ? other$parameterBinders != null : !this$parameterBinders.equals(other$parameterBinders)) return false;
final java.lang.Object this$matcher = this.matcher;
final java.lang.Object other$matcher = other.matcher;
if (this$matcher == null ? other$matcher != null : !this$matcher.equals(other$matcher)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof MethodDelegation.ImplementationDelegate.ForField;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $fieldName = this.fieldName;
result = result * PRIME + ($fieldName == null ? 43 : $fieldName.hashCode());
final java.lang.Object $methodGraphCompiler = this.methodGraphCompiler;
result = result * PRIME + ($methodGraphCompiler == null ? 43 : $methodGraphCompiler.hashCode());
final java.lang.Object $parameterBinders = this.parameterBinders;
result = result * PRIME + ($parameterBinders == null ? 43 : $parameterBinders.hashCode());
final java.lang.Object $matcher = this.matcher;
result = result * PRIME + ($matcher == null ? 43 : $matcher.hashCode());
return result;
}
}
/**
* An implementation delegate for constructing an instance.
*/
class ForConstruction implements ImplementationDelegate {
/**
* The type being constructed.
*/
private final TypeDescription typeDescription;
/**
* The precompiled delegation records.
*/
private final List<MethodDelegationBinder.Record> records;
/**
* Creates an implementation delegate for constructing a new instance.
*
* @param typeDescription The type being constructed.
* @param records The precompiled delegation records.
*/
protected ForConstruction(TypeDescription typeDescription, List<MethodDelegationBinder.Record> records) {
this.typeDescription = typeDescription;
this.records = records;
}
/**
* Creates an implementation delegate for constructing a new instance.
*
* @param typeDescription The type being constructed.
* @param methods The constructors to consider.
* @param methodDelegationBinder The method delegation binder to use.
* @return An appropriate implementation delegate.
*/
protected static ImplementationDelegate of(TypeDescription typeDescription, MethodList<?> methods, MethodDelegationBinder methodDelegationBinder) {
List<MethodDelegationBinder.Record> records = new ArrayList<MethodDelegationBinder.Record>(methods.size());
for (MethodDescription methodDescription : methods) {
records.add(methodDelegationBinder.compile(methodDescription));
}
return new ForConstruction(typeDescription, records);
}
@Override
public InstrumentedType prepare(InstrumentedType instrumentedType) {
return instrumentedType;
}
@Override
public Compiled compile(TypeDescription instrumentedType) {
return new Compiled.ForConstruction(typeDescription, records);
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof MethodDelegation.ImplementationDelegate.ForConstruction)) return false;
final MethodDelegation.ImplementationDelegate.ForConstruction other = (MethodDelegation.ImplementationDelegate.ForConstruction) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$typeDescription = this.typeDescription;
final java.lang.Object other$typeDescription = other.typeDescription;
if (this$typeDescription == null ? other$typeDescription != null : !this$typeDescription.equals(other$typeDescription)) return false;
final java.lang.Object this$records = this.records;
final java.lang.Object other$records = other.records;
if (this$records == null ? other$records != null : !this$records.equals(other$records)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof MethodDelegation.ImplementationDelegate.ForConstruction;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $typeDescription = this.typeDescription;
result = result * PRIME + ($typeDescription == null ? 43 : $typeDescription.hashCode());
final java.lang.Object $records = this.records;
result = result * PRIME + ($records == null ? 43 : $records.hashCode());
return result;
}
}
}
/**
* The appender for implementing a {@link MethodDelegation}.
*/
protected static class Appender implements ByteCodeAppender {
/**
* The implementation target of this implementation.
*/
private final Target implementationTarget;
/**
* The method delegation binder processor which is responsible for implementing the method delegation.
*/
private final MethodDelegationBinder.Processor processor;
/**
* A termination handler for a method delegation binder.
*/
private final MethodDelegationBinder.TerminationHandler terminationHandler;
/**
* The assigner to use.
*/
private final Assigner assigner;
/**
* The compiled implementation delegate.
*/
private final ImplementationDelegate.Compiled compiled;
/**
* Creates a new appender for a method delegation.
*
* @param implementationTarget The implementation target of this implementation.
* @param processor The method delegation binder processor which is responsible for implementing the method delegation.
* @param terminationHandler A termination handler for a method delegation binder.
* @param assigner The assigner to use.
* @param compiled The compiled implementation delegate.
*/
protected Appender(Target implementationTarget, MethodDelegationBinder.Processor processor, MethodDelegationBinder.TerminationHandler terminationHandler, Assigner assigner, ImplementationDelegate.Compiled compiled) {
this.implementationTarget = implementationTarget;
this.processor = processor;
this.terminationHandler = terminationHandler;
this.assigner = assigner;
this.compiled = compiled;
}
@Override
public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
StackManipulation.Size stackSize = new StackManipulation.Compound(compiled.prepare(instrumentedMethod), processor.bind(implementationTarget, instrumentedMethod, terminationHandler, compiled.invoke(), assigner)).apply(methodVisitor, implementationContext);
return new Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize());
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof MethodDelegation.Appender)) return false;
final MethodDelegation.Appender other = (MethodDelegation.Appender) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$implementationTarget = this.implementationTarget;
final java.lang.Object other$implementationTarget = other.implementationTarget;
if (this$implementationTarget == null ? other$implementationTarget != null : !this$implementationTarget.equals(other$implementationTarget)) return false;
final java.lang.Object this$processor = this.processor;
final java.lang.Object other$processor = other.processor;
if (this$processor == null ? other$processor != null : !this$processor.equals(other$processor)) return false;
final java.lang.Object this$terminationHandler = this.terminationHandler;
final java.lang.Object other$terminationHandler = other.terminationHandler;
if (this$terminationHandler == null ? other$terminationHandler != null : !this$terminationHandler.equals(other$terminationHandler)) return false;
final java.lang.Object this$assigner = this.assigner;
final java.lang.Object other$assigner = other.assigner;
if (this$assigner == null ? other$assigner != null : !this$assigner.equals(other$assigner)) return false;
final java.lang.Object this$compiled = this.compiled;
final java.lang.Object other$compiled = other.compiled;
if (this$compiled == null ? other$compiled != null : !this$compiled.equals(other$compiled)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof MethodDelegation.Appender;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $implementationTarget = this.implementationTarget;
result = result * PRIME + ($implementationTarget == null ? 43 : $implementationTarget.hashCode());
final java.lang.Object $processor = this.processor;
result = result * PRIME + ($processor == null ? 43 : $processor.hashCode());
final java.lang.Object $terminationHandler = this.terminationHandler;
result = result * PRIME + ($terminationHandler == null ? 43 : $terminationHandler.hashCode());
final java.lang.Object $assigner = this.assigner;
result = result * PRIME + ($assigner == null ? 43 : $assigner.hashCode());
final java.lang.Object $compiled = this.compiled;
result = result * PRIME + ($compiled == null ? 43 : $compiled.hashCode());
return result;
}
}
/**
* A {@link MethodDelegation} with custom configuration.
*/
public static class WithCustomProperties {
/**
* The ambiguity resolver to use.
*/
private final MethodDelegationBinder.AmbiguityResolver ambiguityResolver;
/**
* The parameter binders to use.
*/
private final List<TargetMethodAnnotationDrivenBinder.ParameterBinder<?>> parameterBinders;
/**
* The matcher to use for filtering relevant methods.
*/
private final ElementMatcher<? super MethodDescription> matcher;
/**
* Creates a new method delegation with custom properties that does not filter any methods.
*
* @param ambiguityResolver The ambiguity resolver to use.
* @param parameterBinders The parameter binders to use.
*/
protected WithCustomProperties(MethodDelegationBinder.AmbiguityResolver ambiguityResolver, List<TargetMethodAnnotationDrivenBinder.ParameterBinder<?>> parameterBinders) {
this(ambiguityResolver, parameterBinders, ElementMatchers.any());
}
/**
* Creates a new method delegation with custom properties.
*
* @param ambiguityResolver The ambiguity resolver to use.
* @param parameterBinders The parameter binders to use.
* @param matcher The matcher to use for filtering relevant methods.
*/
private WithCustomProperties(MethodDelegationBinder.AmbiguityResolver ambiguityResolver, List<TargetMethodAnnotationDrivenBinder.ParameterBinder<?>> parameterBinders, ElementMatcher<? super MethodDescription> matcher) {
this.ambiguityResolver = ambiguityResolver;
this.parameterBinders = parameterBinders;
this.matcher = matcher;
}
/**
* Configures this method delegation to use the supplied ambiguity resolvers when deciding which out of two ore
* more legal delegation targets should be considered.
*
* @param ambiguityResolver The ambiguity resolvers to use in their application order.
* @return A new delegation configuration which also applies the supplied ambiguity resolvers.
*/
public WithCustomProperties withResolvers(MethodDelegationBinder.AmbiguityResolver... ambiguityResolver) {
return withResolvers(Arrays.asList(ambiguityResolver));
}
/**
* Configures this method delegation to use the supplied ambiguity resolvers when deciding which out of two ore
* more legal delegation targets should be considered.
*
* @param ambiguityResolvers The ambiguity resolvers to use in their application order.
* @return A new delegation configuration which also applies the supplied ambiguity resolvers.
*/
public WithCustomProperties withResolvers(List<? extends MethodDelegationBinder.AmbiguityResolver> ambiguityResolvers) {
return new WithCustomProperties(new MethodDelegationBinder.AmbiguityResolver.Compound(CompoundList.of(this.ambiguityResolver, ambiguityResolvers)), parameterBinders, matcher);
}
/**
* Configures this method delegation to use the supplied parameter binders when deciding what value to assign to
* a parameter of a delegation target.
*
* @param parameterBinder The parameter binders to use.
* @return A new delegation configuration which also applies the supplied parameter binders.
*/
public WithCustomProperties withBinders(TargetMethodAnnotationDrivenBinder.ParameterBinder<?>... parameterBinder) {
return withBinders(Arrays.asList(parameterBinder));
}
/**
* Configures this method delegation to use the supplied parameter binders when deciding what value to assign to
* a parameter of a delegation target.
*
* @param parameterBinders The parameter binders to use.
* @return A new delegation configuration which also applies the supplied parameter binders.
*/
public WithCustomProperties withBinders(List<? extends TargetMethodAnnotationDrivenBinder.ParameterBinder<?>> parameterBinders) {
return new WithCustomProperties(ambiguityResolver, CompoundList.of(this.parameterBinders, parameterBinders), matcher);
}
/**
* Configures this method delegation to only consider methods or constructors as a delegation target if they match the supplied matcher.
*
* @param matcher The matcher any delegation target needs to match in order to be considered a for delegation.
* @return A new delegation configuration which only considers methods for delegation if they match the supplied matcher.
*/
public WithCustomProperties filter(ElementMatcher<? super MethodDescription> matcher) {
return new WithCustomProperties(ambiguityResolver, parameterBinders, new ElementMatcher.Junction.Conjunction<MethodDescription>(this.matcher, matcher));
}
/**
* Delegates any intercepted method to invoke a {@code static} method that is declared by the supplied type. To be considered
* a valid delegation target, the target method must be visible and accessible to the instrumented type. This is the case if
* the target type is either public or in the same package as the instrumented type and if the target method is either public
* or non-private and in the same package as the instrumented type. Private methods can only be used as a delegation target if
* the interception is targeting the instrumented type.
*
* @param type The target type for the delegation.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public MethodDelegation to(Class<?> type) {
return to(new TypeDescription.ForLoadedType(type));
}
/**
* Delegates any intercepted method to invoke a {@code static} method that is declared by the supplied type. To be considered
* a valid delegation target, the target method must be visible and accessible to the instrumented type. This is the case if
* the target type is either public or in the same package as the instrumented type and if the target method is either public
* or non-private and in the same package as the instrumented type. Private methods can only be used as a delegation target if
* the delegation is targeting the instrumented type.
*
* @param typeDescription The target type for the delegation.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public MethodDelegation to(TypeDescription typeDescription) {
if (typeDescription.isArray()) {
throw new IllegalArgumentException("Cannot delegate to array " + typeDescription);
} else if (typeDescription.isPrimitive()) {
throw new IllegalArgumentException("Cannot delegate to primitive " + typeDescription);
}
return new MethodDelegation(ImplementationDelegate.ForStaticMethod.of(typeDescription.getDeclaredMethods().filter(ElementMatchers.isStatic().and(matcher)), TargetMethodAnnotationDrivenBinder.of(parameterBinders)), TargetMethodAnnotationDrivenBinder.ParameterBinder.DEFAULTS, MethodDelegationBinder.AmbiguityResolver.DEFAULT);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public MethodDelegation to(Object target) {
return to(target, MethodGraph.Compiler.DEFAULT);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param methodGraphCompiler The method graph compiler to use.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public MethodDelegation to(Object target, MethodGraph.Compiler methodGraphCompiler) {
return to(target, target.getClass(), methodGraphCompiler);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param fieldName The name of the field that is holding the {@code target} instance.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public MethodDelegation to(Object target, String fieldName) {
return to(target, fieldName, MethodGraph.Compiler.DEFAULT);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param fieldName The name of the field that is holding the {@code target} instance.
* @param methodGraphCompiler The method graph compiler to use.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public MethodDelegation to(Object target, String fieldName, MethodGraph.Compiler methodGraphCompiler) {
return to(target, target.getClass(), fieldName, methodGraphCompiler);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param type The most specific type of which {@code target} should be cosnidered. Must be a super type of the target's actual type.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public MethodDelegation to(Object target, Type type) {
return to(target, type, MethodGraph.Compiler.DEFAULT);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param type The most specific type of which {@code target} should be cosnidered. Must be a super type of the target's actual type.
* @param methodGraphCompiler The method graph compiler to use.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public MethodDelegation to(Object target, Type type, MethodGraph.Compiler methodGraphCompiler) {
return to(target, type, String.format("%s$%s", ImplementationDelegate.FIELD_NAME_PREFIX, RandomString.hashOf(target.hashCode())), methodGraphCompiler);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param type The most specific type of which {@code target} should be cosnidered. Must be a super type of the target's actual type.
* @param fieldName The name of the field that is holding the {@code target} instance.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public MethodDelegation to(Object target, Type type, String fieldName) {
return to(target, type, fieldName, MethodGraph.Compiler.DEFAULT);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method that is declared by the supplied type's instance or any
* of its super types. To be considered a valid delegation target, a method must be visible and accessible to the instrumented type.
* This is the case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param target The target instance for the delegation.
* @param type The most specific type of which {@code target} should be cosnidered. Must be a super type of the target's actual type.
* @param fieldName The name of the field that is holding the {@code target} instance.
* @param methodGraphCompiler The method graph compiler to use.
* @return A method delegation that redirects method calls to a static method of the supplied type.
*/
public MethodDelegation to(Object target, Type type, String fieldName, MethodGraph.Compiler methodGraphCompiler) {
TypeDescription.Generic typeDescription = TypeDefinition.Sort.describe(type);
if (!typeDescription.asErasure().isInstance(target)) {
throw new IllegalArgumentException(target + " is not an instance of " + type);
}
return new MethodDelegation(new ImplementationDelegate.ForField.WithInstance(fieldName, methodGraphCompiler, parameterBinders, matcher, target, typeDescription), TargetMethodAnnotationDrivenBinder.ParameterBinder.DEFAULTS, MethodDelegationBinder.AmbiguityResolver.DEFAULT);
}
/**
* Delegates any intercepted method to invoke a constructor of the supplied type. To be considered a valid delegation target,
* a constructor must be visible and accessible to the instrumented type. This is the case if the constructor's declaring type is
* either public or in the same package as the instrumented type and if the constructor is either public or non-private and in
* the same package as the instrumented type. Private constructors can only be used as a delegation target if the delegation is
* targeting the instrumented type.
*
* @param type The type to construct.
* @return A delegation that redirects method calls to a constructor of the supplied type.
*/
public MethodDelegation toConstructor(Class<?> type) {
return toConstructor(new TypeDescription.ForLoadedType(type));
}
/**
* Delegates any intercepted method to invoke a constructor of the supplied type. To be considered a valid delegation target,
* a constructor must be visible and accessible to the instrumented type. This is the case if the constructor's declaring type is
* either public or in the same package as the instrumented type and if the constructor is either public or non-private and in
* the same package as the instrumented type. Private constructors can only be used as a delegation target if the delegation is
* targeting the instrumented type.
*
* @param typeDescription The type to construct.
* @return A delegation that redirects method calls to a constructor of the supplied type.
*/
public MethodDelegation toConstructor(TypeDescription typeDescription) {
return new MethodDelegation(ImplementationDelegate.ForConstruction.of(typeDescription, typeDescription.getDeclaredMethods().filter(ElementMatchers.isConstructor().and(matcher)), TargetMethodAnnotationDrivenBinder.of(parameterBinders)), TargetMethodAnnotationDrivenBinder.ParameterBinder.DEFAULTS, MethodDelegationBinder.AmbiguityResolver.DEFAULT);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method on the instance of the supplied field. To be
* considered a valid delegation target, a method must be visible and accessible to the instrumented type. This is the
* case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param name The field's name.
* @return A delegation that redirects invocations to a method of the specified field's instance.
*/
public MethodDelegation toField(String name) {
return toField(name, FieldLocator.ForClassHierarchy.Factory.INSTANCE);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method on the instance of the supplied field. To be
* considered a valid delegation target, a method must be visible and accessible to the instrumented type. This is the
* case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the delegation is targeting the instrumented type.
*
* @param name The field's name.
* @param fieldLocatorFactory The field locator factory to use.
* @return A delegation that redirects invocations to a method of the specified field's instance.
*/
public MethodDelegation toField(String name, FieldLocator.Factory fieldLocatorFactory) {
return toField(name, fieldLocatorFactory, MethodGraph.Compiler.DEFAULT);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method on the instance of the supplied field. To be
* considered a valid delegation target, a method must be visible and accessible to the instrumented type. This is the
* case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the ddelegation is targeting the instrumented type.
*
* @param name The field's name.
* @param methodGraphCompiler The method graph compiler to use.
* @return A delegation that redirects invocations to a method of the specified field's instance.
*/
public MethodDelegation toField(String name, MethodGraph.Compiler methodGraphCompiler) {
return toField(name, FieldLocator.ForClassHierarchy.Factory.INSTANCE, methodGraphCompiler);
}
/**
* Delegates any intercepted method to invoke a non-{@code static} method on the instance of the supplied field. To be
* considered a valid delegation target, a method must be visible and accessible to the instrumented type. This is the
* case if the method's declaring type is either public or in the same package as the instrumented type and if the method
* is either public or non-private and in the same package as the instrumented type. Private methods can only be used as
* a delegation target if the ddelegation is targeting the instrumented type.
*
* @param name The field's name.
* @param fieldLocatorFactory The field locator factory to use.
* @param methodGraphCompiler The method graph compiler to use.
* @return A delegation that redirects invocations to a method of the specified field's instance.
*/
public MethodDelegation toField(String name, FieldLocator.Factory fieldLocatorFactory, MethodGraph.Compiler methodGraphCompiler) {
return new MethodDelegation(new ImplementationDelegate.ForField.WithLookup(name, methodGraphCompiler, parameterBinders, matcher, fieldLocatorFactory), TargetMethodAnnotationDrivenBinder.ParameterBinder.DEFAULTS, MethodDelegationBinder.AmbiguityResolver.DEFAULT);
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof MethodDelegation.WithCustomProperties)) return false;
final MethodDelegation.WithCustomProperties other = (MethodDelegation.WithCustomProperties) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$ambiguityResolver = this.ambiguityResolver;
final java.lang.Object other$ambiguityResolver = other.ambiguityResolver;
if (this$ambiguityResolver == null ? other$ambiguityResolver != null : !this$ambiguityResolver.equals(other$ambiguityResolver)) return false;
final java.lang.Object this$parameterBinders = this.parameterBinders;
final java.lang.Object other$parameterBinders = other.parameterBinders;
if (this$parameterBinders == null ? other$parameterBinders != null : !this$parameterBinders.equals(other$parameterBinders)) return false;
final java.lang.Object this$matcher = this.matcher;
final java.lang.Object other$matcher = other.matcher;
if (this$matcher == null ? other$matcher != null : !this$matcher.equals(other$matcher)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof MethodDelegation.WithCustomProperties;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $ambiguityResolver = this.ambiguityResolver;
result = result * PRIME + ($ambiguityResolver == null ? 43 : $ambiguityResolver.hashCode());
final java.lang.Object $parameterBinders = this.parameterBinders;
result = result * PRIME + ($parameterBinders == null ? 43 : $parameterBinders.hashCode());
final java.lang.Object $matcher = this.matcher;
result = result * PRIME + ($matcher == null ? 43 : $matcher.hashCode());
return result;
}
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public boolean equals(final java.lang.Object o) {
if (o == this) return true;
if (!(o instanceof MethodDelegation)) return false;
final MethodDelegation other = (MethodDelegation) o;
if (!other.canEqual((java.lang.Object) this)) return false;
final java.lang.Object this$implementationDelegate = this.implementationDelegate;
final java.lang.Object other$implementationDelegate = other.implementationDelegate;
if (this$implementationDelegate == null ? other$implementationDelegate != null : !this$implementationDelegate.equals(other$implementationDelegate)) return false;
final java.lang.Object this$parameterBinders = this.parameterBinders;
final java.lang.Object other$parameterBinders = other.parameterBinders;
if (this$parameterBinders == null ? other$parameterBinders != null : !this$parameterBinders.equals(other$parameterBinders)) return false;
final java.lang.Object this$ambiguityResolver = this.ambiguityResolver;
final java.lang.Object other$ambiguityResolver = other.ambiguityResolver;
if (this$ambiguityResolver == null ? other$ambiguityResolver != null : !this$ambiguityResolver.equals(other$ambiguityResolver)) return false;
final java.lang.Object this$terminationHandler = this.terminationHandler;
final java.lang.Object other$terminationHandler = other.terminationHandler;
if (this$terminationHandler == null ? other$terminationHandler != null : !this$terminationHandler.equals(other$terminationHandler)) return false;
final java.lang.Object this$assigner = this.assigner;
final java.lang.Object other$assigner = other.assigner;
if (this$assigner == null ? other$assigner != null : !this$assigner.equals(other$assigner)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof MethodDelegation;
}
@java.lang.Override
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
public int hashCode() {
final int PRIME = 59;
int result = 1;
final java.lang.Object $implementationDelegate = this.implementationDelegate;
result = result * PRIME + ($implementationDelegate == null ? 43 : $implementationDelegate.hashCode());
final java.lang.Object $parameterBinders = this.parameterBinders;
result = result * PRIME + ($parameterBinders == null ? 43 : $parameterBinders.hashCode());
final java.lang.Object $ambiguityResolver = this.ambiguityResolver;
result = result * PRIME + ($ambiguityResolver == null ? 43 : $ambiguityResolver.hashCode());
final java.lang.Object $terminationHandler = this.terminationHandler;
result = result * PRIME + ($terminationHandler == null ? 43 : $terminationHandler.hashCode());
final java.lang.Object $assigner = this.assigner;
result = result * PRIME + ($assigner == null ? 43 : $assigner.hashCode());
return result;
}
}