// Generated by delombok at Sun Feb 26 12:31:38 KST 2017
package scouter.bytebuddy.dynamic.scaffold.subclass;
import scouter.bytebuddy.ClassFileVersion;
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.MethodGraph;
import scouter.bytebuddy.implementation.Implementation;
import scouter.bytebuddy.matcher.ElementMatchers;
import static scouter.bytebuddy.matcher.ElementMatchers.isVisibleTo;
/**
* An implementation target for creating a subclass of a given type.
*/
public class SubclassImplementationTarget extends Implementation.Target.AbstractBase {
/**
* The origin type identifier to use.
*/
protected final OriginTypeResolver originTypeResolver;
/**
* Creates a new subclass implementation target.
*
* @param instrumentedType The instrumented type.
* @param methodGraph A method graph of the instrumented type.
* @param defaultMethodInvocation The default method invocation mode to apply.
* @param originTypeResolver A resolver for the origin type.
*/
protected SubclassImplementationTarget(TypeDescription instrumentedType, MethodGraph.Linked methodGraph, DefaultMethodInvocation defaultMethodInvocation, OriginTypeResolver originTypeResolver) {
super(instrumentedType, methodGraph, defaultMethodInvocation);
this.originTypeResolver = originTypeResolver;
}
@Override
public Implementation.SpecialMethodInvocation invokeSuper(MethodDescription.SignatureToken token) {
return token.getName().equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME) ? invokeConstructor(token) : invokeMethod(token);
}
/**
* Resolves a special method invocation for a constructor invocation.
*
* @param token A token describing the constructor to be invoked.
* @return A special method invocation for a constructor representing the given method token, if available.
*/
private Implementation.SpecialMethodInvocation invokeConstructor(MethodDescription.SignatureToken token) {
TypeDescription.Generic superClass = instrumentedType.getSuperClass();
MethodList<?> candidates = superClass == null ? new MethodList.Empty<MethodDescription.InGenericShape>() : superClass.getDeclaredMethods().filter(ElementMatchers.hasSignature(token).and(ElementMatchers.isVisibleTo(instrumentedType)));
return candidates.size() == 1 ? Implementation.SpecialMethodInvocation.Simple.of(candidates.getOnly(), instrumentedType.getSuperClass().asErasure()) : Implementation.SpecialMethodInvocation.Illegal.INSTANCE;
}
/**
* Resolves a special method invocation for a non-constructor invocation.
*
* @param token A token describing the method to be invoked.
* @return A special method invocation for a method representing the given method token, if available.
*/
private Implementation.SpecialMethodInvocation invokeMethod(MethodDescription.SignatureToken token) {
MethodGraph.Node methodNode = methodGraph.getSuperClassGraph().locate(token);
return methodNode.getSort().isUnique() ? Implementation.SpecialMethodInvocation.Simple.of(methodNode.getRepresentative(), instrumentedType.getSuperClass().asErasure()) : Implementation.SpecialMethodInvocation.Illegal.INSTANCE;
}
@Override
public TypeDefinition getOriginType() {
return originTypeResolver.identify(instrumentedType);
}
/**
* Responsible for identifying the origin type that an implementation target represents when
* {@link Implementation.Target#getOriginType()} is invoked.
*/
public enum OriginTypeResolver {
/**
* Identifies the super type of an instrumented type as the origin class.
*/
SUPER_CLASS {
@Override
protected TypeDefinition identify(TypeDescription typeDescription) {
return typeDescription.getSuperClass();
}
},
/**
* Identifies the instrumented type as its own origin type.
*/
LEVEL_TYPE {
@Override
protected TypeDefinition identify(TypeDescription typeDescription) {
return typeDescription;
}
};
/**
* Identifies the origin type to a given type description.
*
* @param typeDescription The type description for which an origin type should be identified.
* @return The origin type to the given type description.
*/
protected abstract TypeDefinition identify(TypeDescription typeDescription);
}
/**
* A factory for creating a {@link SubclassImplementationTarget}.
*/
public enum Factory implements Implementation.Target.Factory {
/**
* A factory creating a subclass implementation target with a {@link OriginTypeResolver#SUPER_CLASS}.
*/
SUPER_CLASS(OriginTypeResolver.SUPER_CLASS),
/**
* A factory creating a subclass implementation target with a {@link OriginTypeResolver#LEVEL_TYPE}.
*/
LEVEL_TYPE(OriginTypeResolver.LEVEL_TYPE);
/**
* The origin type resolver that this factory hands to the created {@link SubclassImplementationTarget}.
*/
private final OriginTypeResolver originTypeResolver;
/**
* Creates a new factory.
*
* @param originTypeResolver The origin type resolver that this factory hands to the created {@link SubclassImplementationTarget}.
*/
Factory(OriginTypeResolver originTypeResolver) {
this.originTypeResolver = originTypeResolver;
}
@Override
public Implementation.Target make(TypeDescription instrumentedType, MethodGraph.Linked methodGraph, ClassFileVersion classFileVersion) {
return new SubclassImplementationTarget(instrumentedType, methodGraph, DefaultMethodInvocation.of(classFileVersion), originTypeResolver);
}
}
@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 SubclassImplementationTarget)) return false;
final SubclassImplementationTarget other = (SubclassImplementationTarget) o;
if (!other.canEqual((java.lang.Object) this)) return false;
if (!super.equals(o)) return false;
final java.lang.Object this$originTypeResolver = this.originTypeResolver;
final java.lang.Object other$originTypeResolver = other.originTypeResolver;
if (this$originTypeResolver == null ? other$originTypeResolver != null : !this$originTypeResolver.equals(other$originTypeResolver)) return false;
return true;
}
@java.lang.SuppressWarnings("all")
@javax.annotation.Generated("lombok")
protected boolean canEqual(final java.lang.Object other) {
return other instanceof SubclassImplementationTarget;
}
@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 $originTypeResolver = this.originTypeResolver;
result = result * PRIME + ($originTypeResolver == null ? 43 : $originTypeResolver.hashCode());
return result;
}
}