package org.stagemonitor.core.instrument;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import static net.bytebuddy.matcher.ElementMatchers.any;
import static net.bytebuddy.matcher.ElementMatchers.declaresMethod;
import static net.bytebuddy.matcher.ElementMatchers.is;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.returns;
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
public class OverridesMethodElementMatcher implements ElementMatcher<MethodDescription> {
private final ElementMatcher<? super MethodDescription> extraMethodMatcher;
private final ElementMatcher<? super TypeDescription> superClassMatcher;
public static OverridesMethodElementMatcher overridesSuperMethod() {
return new OverridesMethodElementMatcher();
}
public static OverridesMethodElementMatcher overridesSuperMethodThat(ElementMatcher<? super MethodDescription> methodElementMatcher) {
return new OverridesMethodElementMatcher(methodElementMatcher);
}
private OverridesMethodElementMatcher() {
this(any());
}
private OverridesMethodElementMatcher(ElementMatcher<? super MethodDescription> extraMethodMatcher) {
this(extraMethodMatcher, not(is(TypeDescription.ForLoadedType.OBJECT)));
}
private OverridesMethodElementMatcher(ElementMatcher<? super MethodDescription> extraMethodMatcher, ElementMatcher<? super TypeDescription> superClassMatcher) {
this.extraMethodMatcher = extraMethodMatcher;
this.superClassMatcher = superClassMatcher;
}
public ElementMatcher<MethodDescription> onSuperClassesThat(ElementMatcher<? super TypeDescription> superClassMatcher) {
return new OverridesMethodElementMatcher(extraMethodMatcher, superClassMatcher);
}
@Override
public boolean matches(MethodDescription targetMethod) {
TypeDescription superClass = targetMethod.getDeclaringType().asErasure();
do {
superClass = superClass.getSuperClass().asErasure();
if (declaresMethod(named(targetMethod.getName())
.and(returns(targetMethod.getReturnType().asErasure()))
.and(takesArguments(targetMethod.getParameters().asTypeList().asErasures()))
.and(extraMethodMatcher))
.matches(superClass)) {
return true;
}
} while (superClassMatcher.matches(superClass));
return false;
}
}