// 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.type.TypeDescription; import scouter.bytebuddy.description.type.TypeList; import scouter.bytebuddy.dynamic.scaffold.FieldLocator; import scouter.bytebuddy.dynamic.scaffold.InstrumentedType; import scouter.bytebuddy.implementation.bytecode.ByteCodeAppender; import scouter.bytebuddy.implementation.bytecode.StackManipulation; import scouter.bytebuddy.implementation.bytecode.assign.Assigner; import scouter.bytebuddy.implementation.bytecode.collection.ArrayFactory; import scouter.bytebuddy.implementation.bytecode.constant.MethodConstant; import scouter.bytebuddy.implementation.bytecode.member.FieldAccess; import scouter.bytebuddy.implementation.bytecode.member.MethodInvocation; import scouter.bytebuddy.implementation.bytecode.member.MethodReturn; import scouter.bytebuddy.implementation.bytecode.member.MethodVariableAccess; 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.InvocationHandler; import java.util.ArrayList; import java.util.List; import static scouter.bytebuddy.matcher.ElementMatchers.genericFieldType; /** * An adapter for adapting an {@link java.lang.reflect.InvocationHandler}. The adapter allows the invocation handler * to also intercept method calls to non-interface methods. */ public abstract class InvocationHandlerAdapter implements Implementation { /** * A type description of the {@link InvocationHandler}. */ private static final TypeDescription.Generic INVOCATION_HANDLER_TYPE = new TypeDescription.Generic.OfNonGenericType.ForLoadedType(InvocationHandler.class); /** * Indicates that a value should not be cached. */ private static final boolean NO_CACHING = false; /** * Indicates that a {@link java.lang.reflect.Method} should be cached. */ protected static final boolean CACHING = true; /** * The name of the field for storing an invocation handler. */ protected final String fieldName; /** * The assigner that is used for assigning the return invocation handler's return value to the * intercepted method's return value. */ protected final Assigner assigner; /** * Determines if the {@link java.lang.reflect.Method} instances that are handed to the intercepted methods are * cached in {@code static} fields. */ protected final boolean cacheMethods; /** * Creates a new invocation handler for a given field. * * @param fieldName The name of the field. * @param cacheMethods Determines if the {@link java.lang.reflect.Method} instances that are handed to the * intercepted methods are cached in {@code static} fields. * @param assigner The assigner to apply when defining this implementation. */ protected InvocationHandlerAdapter(String fieldName, boolean cacheMethods, Assigner assigner) { this.fieldName = fieldName; this.cacheMethods = cacheMethods; this.assigner = assigner; } /** * Creates an implementation for any instance of an {@link java.lang.reflect.InvocationHandler} that delegates * all method interceptions to the given instance which will be stored in a {@code static} field. * * @param invocationHandler The invocation handler to which all method calls are delegated. * @return An implementation that delegates all method interceptions to the given invocation handler. */ public static InvocationHandlerAdapter of(InvocationHandler invocationHandler) { return of(invocationHandler, String.format("%s$%s", ForInstance.PREFIX, RandomString.hashOf(invocationHandler.hashCode()))); } /** * Creates an implementation for any instance of an {@link java.lang.reflect.InvocationHandler} that delegates * all method interceptions to the given instance which will be stored in a {@code static} field. * * @param invocationHandler The invocation handler to which all method calls are delegated. * @param fieldName The name of the field. * @return An implementation that delegates all method interceptions to the given invocation handler. */ public static InvocationHandlerAdapter of(InvocationHandler invocationHandler, String fieldName) { return new ForInstance(fieldName, CACHING, Assigner.DEFAULT, invocationHandler); } /** * Creates an implementation for any {@link java.lang.reflect.InvocationHandler} that delegates * all method interceptions to a field with the given name. This field has to be of a subtype of invocation * handler and needs to be set before any invocations are intercepted. Otherwise, a {@link java.lang.NullPointerException} * will be thrown. * * @param name The name of the field. * @return An implementation that delegates all method interceptions to an instance field of the given name. */ public static InvocationHandlerAdapter toField(String name) { return toField(name, FieldLocator.ForClassHierarchy.Factory.INSTANCE); } /** * Creates an implementation for any {@link java.lang.reflect.InvocationHandler} that delegates * all method interceptions to a field with the given name. This field has to be of a subtype of invocation * handler and needs to be set before any invocations are intercepted. Otherwise, a {@link java.lang.NullPointerException} * will be thrown. * * @param name The name of the field. * @param fieldLocatorFactory The field locator factory * @return An implementation that delegates all method interceptions to an instance field of the given name. */ public static InvocationHandlerAdapter toField(String name, FieldLocator.Factory fieldLocatorFactory) { return new ForField(name, CACHING, Assigner.DEFAULT, fieldLocatorFactory); } /** * Returns a list of stack manipulations that loads all arguments of an instrumented method. * * @param instrumentedMethod The method that is instrumented. * @return A list of stack manipulation that loads all arguments of an instrumented method. */ private List<StackManipulation> argumentValuesOf(MethodDescription instrumentedMethod) { TypeList.Generic parameterTypes = instrumentedMethod.getParameters().asTypeList(); List<StackManipulation> instruction = new ArrayList<StackManipulation>(parameterTypes.size()); int currentIndex = 1; for (TypeDescription.Generic parameterType : parameterTypes) { instruction.add(new StackManipulation.Compound(MethodVariableAccess.of(parameterType).loadFrom(currentIndex), assigner.assign(parameterType, TypeDescription.Generic.OBJECT, Assigner.Typing.STATIC))); currentIndex += parameterType.getStackSize().getSize(); } return instruction; } /** * By default, any {@link java.lang.reflect.Method} instance that is handed over to an * {@link java.lang.reflect.InvocationHandler} is cached in a static field. By invoking this method, * this feature can be disabled. * * @return A similar invocation handler adapter that applies caching. */ public abstract AssignerConfigurable withoutMethodCache(); /** * Applies an implementation that delegates to a invocation handler. * * @param methodVisitor The method visitor for writing the byte code to. * @param implementationContext The implementation context for the current implementation. * @param instrumentedMethod The method that is instrumented. * @param preparingManipulation A stack manipulation that applies any preparation to the operand stack. * @param fieldDescription The field that contains the value for the invocation handler. * @return The size of the applied assignment. */ protected ByteCodeAppender.Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod, StackManipulation preparingManipulation, FieldDescription fieldDescription) { if (instrumentedMethod.isStatic()) { throw new IllegalStateException("It is not possible to apply an invocation handler onto the static method " + instrumentedMethod); } StackManipulation.Size stackSize = new StackManipulation.Compound(preparingManipulation, FieldAccess.forField(fieldDescription).read(), MethodVariableAccess.loadThis(), cacheMethods ? MethodConstant.forMethod(instrumentedMethod.asDefined()).cached() : MethodConstant.forMethod(instrumentedMethod.asDefined()), ArrayFactory.forType(TypeDescription.Generic.OBJECT).withValues(argumentValuesOf(instrumentedMethod)), MethodInvocation.invoke(INVOCATION_HANDLER_TYPE.getDeclaredMethods().getOnly()), assigner.assign(TypeDescription.Generic.OBJECT, instrumentedMethod.getReturnType(), Assigner.Typing.DYNAMIC), MethodReturn.of(instrumentedMethod.getReturnType())).apply(methodVisitor, implementationContext); return new ByteCodeAppender.Size(stackSize.getMaximalSize(), instrumentedMethod.getStackSize()); } /** * Allows for the configuration of an {@link Assigner} * of an {@link InvocationHandlerAdapter}. */ protected interface AssignerConfigurable extends Implementation { /** * Configures an assigner to use with this invocation handler adapter. * * @param assigner The assigner to apply when defining this implementation. * @return This instrumentation with the given {@code assigner} configured. */ Implementation withAssigner(Assigner assigner); } /** * An implementation of an {@link InvocationHandlerAdapter} that delegates method * invocations to an adapter that is stored in a static field. */ protected static class ForInstance extends InvocationHandlerAdapter implements AssignerConfigurable { /** * The prefix for field that are created for storing the instrumented value. */ private static final String PREFIX = "invocationHandler"; /** * The invocation handler to which method interceptions are to be delegated. */ protected final InvocationHandler invocationHandler; /** * Creates a new invocation handler adapter for delegating invocations to an invocation handler that is stored * in a static field. * * @param fieldName The name of the field. * @param cacheMethods Determines if the {@link java.lang.reflect.Method} instances that are handed to the * intercepted methods are cached in {@code static} fields. * @param assigner The assigner to apply when defining this implementation. * @param invocationHandler The invocation handler to which all method calls are delegated. */ protected ForInstance(String fieldName, boolean cacheMethods, Assigner assigner, InvocationHandler invocationHandler) { super(fieldName, cacheMethods, assigner); this.invocationHandler = invocationHandler; } @Override public AssignerConfigurable withoutMethodCache() { return new ForInstance(fieldName, NO_CACHING, assigner, invocationHandler); } @Override public Implementation withAssigner(Assigner assigner) { return new ForInstance(fieldName, cacheMethods, assigner, invocationHandler); } @Override public InstrumentedType prepare(InstrumentedType instrumentedType) { return instrumentedType.withField(new FieldDescription.Token(fieldName, Opcodes.ACC_SYNTHETIC | Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC, INVOCATION_HANDLER_TYPE)).withInitializer(new LoadedTypeInitializer.ForStaticField(fieldName, invocationHandler)); } @Override public ByteCodeAppender appender(Target implementationTarget) { return new Appender(implementationTarget.getInstrumentedType()); } /** * An appender for implementing the {@link ForInstance}. */ protected class Appender implements ByteCodeAppender { /** * The instrumented type for which the methods are being intercepted. */ private final TypeDescription instrumentedType; /** * Creates a new appender. * * @param instrumentedType The type that is instrumented. */ protected Appender(TypeDescription instrumentedType) { this.instrumentedType = instrumentedType; } @Override public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { return ForInstance.this.apply(methodVisitor, implementationContext, instrumentedMethod, StackManipulation.Trivial.INSTANCE, instrumentedType.getDeclaredFields().filter(ElementMatchers.named(fieldName).and(ElementMatchers.genericFieldType(INVOCATION_HANDLER_TYPE))).getOnly()); } private InvocationHandlerAdapter getInvocationHandlerAdapter() { return ForInstance.this; } // HE: Remove when Lombok support for getOuter is added. @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && instrumentedType.equals(((Appender) other).instrumentedType) && ForInstance.this.equals(((Appender) other).getInvocationHandlerAdapter()); } // HE: Remove when Lombok support for getOuter is added. /** * Returns the outer class. * * @return The outer class of this instance. */ @Override public int hashCode() { return 31 * ForInstance.this.hashCode() + instrumentedType.hashCode(); } } @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 InvocationHandlerAdapter.ForInstance)) return false; final InvocationHandlerAdapter.ForInstance other = (InvocationHandlerAdapter.ForInstance) o; if (!other.canEqual((java.lang.Object) this)) return false; if (!super.equals(o)) return false; final java.lang.Object this$invocationHandler = this.invocationHandler; final java.lang.Object other$invocationHandler = other.invocationHandler; if (this$invocationHandler == null ? other$invocationHandler != null : !this$invocationHandler.equals(other$invocationHandler)) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof InvocationHandlerAdapter.ForInstance; } @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 $invocationHandler = this.invocationHandler; result = result * PRIME + ($invocationHandler == null ? 43 : $invocationHandler.hashCode()); return result; } } /** * An implementation of an {@link InvocationHandlerAdapter} that delegates method * invocations to an adapter that is stored in an instance field. */ protected static class ForField extends InvocationHandlerAdapter implements AssignerConfigurable { /** * The field locator factory to use. */ private final FieldLocator.Factory fieldLocatorFactory; /** * Creates a new invocation handler adapter that loads its value from a field. * * @param fieldName The name of the field. * @param cacheMethods Determines if the {@link java.lang.reflect.Method} instances that are handed to the * intercepted methods are cached in {@code static} fields. * @param assigner The assigner to apply when defining this implementation. * @param fieldLocatorFactory The field locator factory to use. */ protected ForField(String fieldName, boolean cacheMethods, Assigner assigner, FieldLocator.Factory fieldLocatorFactory) { super(fieldName, cacheMethods, assigner); this.fieldLocatorFactory = fieldLocatorFactory; } @Override public AssignerConfigurable withoutMethodCache() { return new ForField(fieldName, NO_CACHING, assigner, fieldLocatorFactory); } @Override public Implementation withAssigner(Assigner assigner) { return new ForField(fieldName, cacheMethods, assigner, fieldLocatorFactory); } @Override public InstrumentedType prepare(InstrumentedType instrumentedType) { return instrumentedType; } @Override public ByteCodeAppender appender(Target implementationTarget) { FieldLocator.Resolution resolution = fieldLocatorFactory.make(implementationTarget.getInstrumentedType()).locate(fieldName); if (!resolution.isResolved()) { throw new IllegalStateException("Could not find a field named \'" + fieldName + "\' for " + implementationTarget.getInstrumentedType()); } else if (!resolution.getField().getType().asErasure().isAssignableTo(InvocationHandler.class)) { throw new IllegalStateException("Field " + resolution.getField() + " does not declare a type that is assignable to invocation handler"); } return new Appender(implementationTarget.getInstrumentedType(), resolution.getField()); } /** * An appender for implementing the {@link ForField}. */ protected class Appender implements ByteCodeAppender { /** * The type that is subject of the instrumentation. */ private final TypeDescription instrumentedType; /** * The field that contains the invocation handler. */ private final FieldDescription fieldDescription; /** * Creates a new appender. * * @param instrumentedType The type that is instrumented. * @param fieldDescription The field that contains the invocation handler. */ protected Appender(TypeDescription instrumentedType, FieldDescription fieldDescription) { this.instrumentedType = instrumentedType; this.fieldDescription = fieldDescription; } @Override public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) { return ForField.this.apply(methodVisitor, implementationContext, instrumentedMethod, fieldDescription.isStatic() ? StackManipulation.Trivial.INSTANCE : MethodVariableAccess.loadThis(), fieldDescription); } // HE: Remove when Lombok support for getOuter is added. @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && instrumentedType.equals(((Appender) other).instrumentedType) && fieldDescription.equals(((Appender) other).fieldDescription) && ForField.this.equals(((Appender) other).getInvocationHandlerAdapter()); } /** * Returns the outer class. * * @return The outer class. */ private InvocationHandlerAdapter getInvocationHandlerAdapter() { return ForField.this; } // HE: Remove when Lombok support for getOuter is added. @Override public int hashCode() { return 31 * (31 * ForField.this.hashCode() + instrumentedType.hashCode()) + fieldDescription.hashCode(); } } @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 InvocationHandlerAdapter.ForField)) return false; final InvocationHandlerAdapter.ForField other = (InvocationHandlerAdapter.ForField) 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 InvocationHandlerAdapter.ForField; } @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 InvocationHandlerAdapter)) return false; final InvocationHandlerAdapter other = (InvocationHandlerAdapter) 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$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; if (this.cacheMethods != other.cacheMethods) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof InvocationHandlerAdapter; } @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 $assigner = this.assigner; result = result * PRIME + ($assigner == null ? 43 : $assigner.hashCode()); result = result * PRIME + (this.cacheMethods ? 79 : 97); return result; } }