package net.bytebuddy.dynamic.scaffold.inline;
import lombok.EqualsAndHashCode;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.matcher.LatentMatcher;
import static net.bytebuddy.matcher.ElementMatchers.*;
/**
* A latent method matcher that identifies methods to instrument when redefining or rebasing a type.
*/
@EqualsAndHashCode
public class InliningImplementationMatcher implements LatentMatcher<MethodDescription> {
/**
* A method matcher that matches any ignored method.
*/
private final LatentMatcher<? super MethodDescription> ignoredMethods;
/**
* A method matcher that matches any predefined method.
*/
private final ElementMatcher<? super MethodDescription> predefinedMethodSignatures;
/**
* Creates a new inline implementation matcher.
*
* @param ignoredMethods A method matcher that matches any ignored method.
* @param predefinedMethodSignatures A method matcher that matches any predefined method.
*/
protected InliningImplementationMatcher(LatentMatcher<? super MethodDescription> ignoredMethods,
ElementMatcher<? super MethodDescription> predefinedMethodSignatures) {
this.ignoredMethods = ignoredMethods;
this.predefinedMethodSignatures = predefinedMethodSignatures;
}
/**
* Creates a matcher where only overridable or declared methods are matched unless those are ignored. Methods that
* are declared by the target type are only matched if they are not ignored. Declared methods that are not found on the
* target type are always matched.
*
* @param ignoredMethods A method matcher that matches any ignored method.
* @param originalType The original type of the instrumentation before adding any user methods.
* @return A latent method matcher that identifies any method to instrument for a rebasement or redefinition.
*/
protected static LatentMatcher<MethodDescription> of(LatentMatcher<? super MethodDescription> ignoredMethods, TypeDescription originalType) {
ElementMatcher.Junction<MethodDescription> predefinedMethodSignatures = none();
for (MethodDescription methodDescription : originalType.getDeclaredMethods()) {
ElementMatcher.Junction<MethodDescription> signature = methodDescription.isConstructor()
? isConstructor()
: ElementMatchers.<MethodDescription>named(methodDescription.getName());
signature = signature.and(returns(methodDescription.getReturnType().asErasure()));
signature = signature.and(takesArguments(methodDescription.getParameters().asTypeList().asErasures()));
predefinedMethodSignatures = predefinedMethodSignatures.or(signature);
}
return new InliningImplementationMatcher(ignoredMethods, predefinedMethodSignatures);
}
@Override
public ElementMatcher<? super MethodDescription> resolve(TypeDescription typeDescription) {
return (ElementMatcher<? super MethodDescription>) not(ignoredMethods.resolve(typeDescription))
.and(isVirtual().and(not(isFinal())).or(isDeclaredBy(typeDescription)))
.or(isDeclaredBy(typeDescription).and(not(predefinedMethodSignatures)));
}
}