com.fitbur.mockito.bytebuddy.dynamic.scaffold.inline.InliningImplementationMatcher Maven / Gradle / Ivy
The newest version!
package com.fitbur.mockito.bytebuddy.dynamic.scaffold.inline;
import com.fitbur.mockito.bytebuddy.description.method.MethodDescription;
import com.fitbur.mockito.bytebuddy.description.type.TypeDescription;
import com.fitbur.mockito.bytebuddy.matcher.ElementMatcher;
import com.fitbur.mockito.bytebuddy.matcher.ElementMatchers;
import com.fitbur.mockito.bytebuddy.matcher.LatentMatcher;
import static com.fitbur.mockito.bytebuddy.matcher.ElementMatchers.*;
/**
* A latent method matcher that identifies methods to instrument when redefining or rebasing a type.
*/
public class InliningImplementationMatcher implements LatentMatcher {
/**
* 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 of(LatentMatcher super MethodDescription> ignoredMethods, TypeDescription originalType) {
ElementMatcher.Junction predefinedMethodSignatures = none();
for (MethodDescription methodDescription : originalType.getDeclaredMethods()) {
ElementMatcher.Junction signature = methodDescription.isConstructor()
? isConstructor()
: ElementMatchers.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)));
}
@Override
public boolean equals(Object other) {
return this == other || !(other == null || getClass() != other.getClass())
&& ignoredMethods.equals(((InliningImplementationMatcher) other).ignoredMethods)
&& predefinedMethodSignatures.equals(((InliningImplementationMatcher) other).predefinedMethodSignatures);
}
@Override
public int hashCode() {
return 31 * ignoredMethods.hashCode() + predefinedMethodSignatures.hashCode();
}
@Override
public String toString() {
return "InliningImplementationMatcher{" +
"ignoredMethods=" + ignoredMethods +
", predefinedMethodSignatures=" + predefinedMethodSignatures +
'}';
}
}