// Generated by delombok at Sun Feb 26 12:31:38 KST 2017 package scouter.bytebuddy.implementation.bytecode.constant; import scouter.bytebuddy.description.method.MethodDescription; import scouter.bytebuddy.description.type.TypeDescription; import scouter.bytebuddy.implementation.Implementation; import scouter.bytebuddy.implementation.bytecode.StackManipulation; import scouter.bytebuddy.implementation.bytecode.collection.ArrayFactory; import scouter.bytebuddy.implementation.bytecode.member.FieldAccess; import scouter.bytebuddy.implementation.bytecode.member.MethodInvocation; import scouter.bytebuddy.jar.asm.MethodVisitor; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * Represents the creation of a {@link java.lang.reflect.Method} value which can be created from a given * set of constant pool values and can therefore be considered a constant in the broader meaning. */ public abstract class MethodConstant implements StackManipulation { /** * The internal name of the {@link Class} type. */ private static final String CLASS_TYPE_INTERNAL_NAME = "java/lang/Class"; /** * A description of the method to be loaded onto the stack. */ protected final MethodDescription.InDefinedShape methodDescription; /** * Creates a new method constant. * * @param methodDescription The method description for which the {@link java.lang.reflect.Method} representation * should be created. */ protected MethodConstant(MethodDescription.InDefinedShape methodDescription) { this.methodDescription = methodDescription; } /** * Creates a stack manipulation that loads a method constant onto the operand stack. * * @param methodDescription The method to be loaded onto the stack. * @return A stack manipulation that assigns a method constant for the given method description. */ public static CanCache forMethod(MethodDescription.InDefinedShape methodDescription) { if (methodDescription.isTypeInitializer()) { return CanCacheIllegal.INSTANCE; } else if (methodDescription.isConstructor()) { return new ForConstructor(methodDescription); } else { return new ForMethod(methodDescription); } } /** * Returns a list of type constant load operations for the given list of parameters. * * @param parameterTypes A list of all type descriptions that should be represented as type constant * load operations. * @return A corresponding list of type constant load operations. */ private static List<StackManipulation> typeConstantsFor(List<TypeDescription> parameterTypes) { List<StackManipulation> typeConstants = new ArrayList<StackManipulation>(parameterTypes.size()); for (TypeDescription parameterType : parameterTypes) { typeConstants.add(ClassConstant.of(parameterType)); } return typeConstants; } @Override public boolean isValid() { return true; } @Override public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { return new Compound(preparation(), ArrayFactory.forType(new TypeDescription.Generic.OfNonGenericType.ForLoadedType(Class.class)).withValues(typeConstantsFor(methodDescription.getParameters().asTypeList().asErasures())), MethodInvocation.invoke(accessorMethod())).apply(methodVisitor, implementationContext); } /** * Returns a stack manipulation that loads the values that are required for loading a method constant onto the operand stack. * * @return A stack manipulation for loading a method or constructor onto the operand stack. */ protected abstract StackManipulation preparation(); /** * Returns the method for loading a declared method or constructor onto the operand stack. * * @return The method for loading a declared method or constructor onto the operand stack. */ protected abstract MethodDescription accessorMethod(); /** * Returns a cached version of this method constant as specified by {@link CachedMethod} and {@link CachedConstructor}. * * @return A cached version of this method constant. */ public StackManipulation cached() { return methodDescription.isConstructor() ? new CachedConstructor(this) : new CachedMethod(this); } /** * Represents a method constant that cannot be represented by Java's reflection API. */ protected enum CanCacheIllegal implements CanCache { /** * The singleton instance. */ INSTANCE; @Override public StackManipulation cached() { return Illegal.INSTANCE; } @Override public boolean isValid() { return false; } @Override public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { return Illegal.INSTANCE.apply(methodVisitor, implementationContext); } } /** * Represents a {@link MethodConstant} that is * directly loaded onto the operand stack without caching the value. Since the look-up of a Java method bares * some costs that sometimes need to be avoided, such a stack manipulation offers a convenience method for * defining this loading instruction as the retrieval of a field value that is initialized in the instrumented * type's type initializer. */ public interface CanCache extends StackManipulation { /** * Returns this method constant as a cached version. * * @return A cached version of the method constant that is represented by this instance. */ StackManipulation cached(); } /** * Creates a {@link MethodConstant} for loading * a {@link java.lang.reflect.Method} instance onto the operand stack. */ protected static class ForMethod extends MethodConstant implements CanCache { /** * Creates a new {@link MethodConstant} for * creating a {@link java.lang.reflect.Method} instance. * * @param methodDescription The method to be loaded onto the stack. */ protected ForMethod(MethodDescription.InDefinedShape methodDescription) { super(methodDescription); } @Override protected StackManipulation preparation() { return new Compound(ClassConstant.of(methodDescription.getDeclaringType()), new TextConstant(methodDescription.getInternalName())); } @Override protected MethodDescription accessorMethod() { try { return new MethodDescription.ForLoadedMethod(Class.class.getMethod("getDeclaredMethod", String.class, Class[].class)); } catch (NoSuchMethodException exception) { throw new IllegalStateException("Cannot locate Class::getDeclaredMethod", exception); } } } /** * Creates a {@link MethodConstant} for loading * a {@link java.lang.reflect.Constructor} instance onto the operand stack. */ protected static class ForConstructor extends MethodConstant implements CanCache { /** * Creates a new {@link MethodConstant} for * creating a {@link java.lang.reflect.Constructor} instance. * * @param methodDescription The constructor to be loaded onto the stack. */ protected ForConstructor(MethodDescription.InDefinedShape methodDescription) { super(methodDescription); } @Override protected StackManipulation preparation() { return ClassConstant.of(methodDescription.getDeclaringType()); } @Override protected MethodDescription accessorMethod() { try { return new MethodDescription.ForLoadedMethod(Class.class.getMethod("getDeclaredConstructor", Class[].class)); } catch (NoSuchMethodException exception) { throw new IllegalStateException("Cannot locate Class::getDeclaredConstructor", exception); } } } /** * Represents a cached method for a {@link MethodConstant}. */ protected static class CachedMethod implements StackManipulation { /** * A description of the {@link java.lang.reflect.Method} type. */ private static final TypeDescription METHOD_TYPE = new TypeDescription.ForLoadedType(Method.class); /** * The stack manipulation that is represented by this caching wrapper. */ private final StackManipulation methodConstant; /** * Creates a new cached {@link MethodConstant}. * * @param methodConstant The method constant to store in the field cache. */ protected CachedMethod(StackManipulation methodConstant) { this.methodConstant = methodConstant; } @Override public boolean isValid() { return methodConstant.isValid(); } @Override public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { return FieldAccess.forField(implementationContext.cache(methodConstant, METHOD_TYPE)).read().apply(methodVisitor, implementationContext); } @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 MethodConstant.CachedMethod)) return false; final MethodConstant.CachedMethod other = (MethodConstant.CachedMethod) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$methodConstant = this.methodConstant; final java.lang.Object other$methodConstant = other.methodConstant; if (this$methodConstant == null ? other$methodConstant != null : !this$methodConstant.equals(other$methodConstant)) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodConstant.CachedMethod; } @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 $methodConstant = this.methodConstant; result = result * PRIME + ($methodConstant == null ? 43 : $methodConstant.hashCode()); return result; } } /** * Represents a cached constructor for a {@link MethodConstant}. */ protected static class CachedConstructor implements StackManipulation { /** * A description of the {@link java.lang.reflect.Constructor} type. */ private static final TypeDescription CONSTRUCTOR_TYPE = new TypeDescription.ForLoadedType(Constructor.class); /** * The stack manipulation that is represented by this caching wrapper. */ private final StackManipulation constructorConstant; /** * Creates a new cached {@link MethodConstant}. * * @param constructorConstant The method constant to store in the field cache. */ protected CachedConstructor(StackManipulation constructorConstant) { this.constructorConstant = constructorConstant; } @Override public boolean isValid() { return constructorConstant.isValid(); } @Override public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext) { return FieldAccess.forField(implementationContext.cache(constructorConstant, CONSTRUCTOR_TYPE)).read().apply(methodVisitor, implementationContext); } @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 MethodConstant.CachedConstructor)) return false; final MethodConstant.CachedConstructor other = (MethodConstant.CachedConstructor) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$constructorConstant = this.constructorConstant; final java.lang.Object other$constructorConstant = other.constructorConstant; if (this$constructorConstant == null ? other$constructorConstant != null : !this$constructorConstant.equals(other$constructorConstant)) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodConstant.CachedConstructor; } @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 $constructorConstant = this.constructorConstant; result = result * PRIME + ($constructorConstant == null ? 43 : $constructorConstant.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 MethodConstant)) return false; final MethodConstant other = (MethodConstant) o; if (!other.canEqual((java.lang.Object) this)) return false; final java.lang.Object this$methodDescription = this.methodDescription; final java.lang.Object other$methodDescription = other.methodDescription; if (this$methodDescription == null ? other$methodDescription != null : !this$methodDescription.equals(other$methodDescription)) return false; return true; } @java.lang.SuppressWarnings("all") @javax.annotation.Generated("lombok") protected boolean canEqual(final java.lang.Object other) { return other instanceof MethodConstant; } @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 $methodDescription = this.methodDescription; result = result * PRIME + ($methodDescription == null ? 43 : $methodDescription.hashCode()); return result; } }