I have an interface:
public interface JustToCheckInterface {
@MyCheck(feature = "occurrence-logging")
void log();
void log2();
@MyCheck(feature = "check-logging")
void log3();
}
and implementation:
@Component
public class JustToCheck implements JustToCheckInterface {
public void log() {
System.out.println("hello");
}
@MyCheck(feature = "check-no-logging")
public void log2() {
System.out.println("hello2");
}
public void log3() {
System.out.println("hello3");
}
}
I've created annotation (the one is used in my interface and in spring component):
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Documented
public @interface MyCheck {
@Required
String feature();
}
and advisor:
@Component
public class MyAdvisor extends AbstractPointcutAdvisor {
@Autowired
private MyMethodInterceptor myMethodInterceptor;
private final StaticMethodMatcherPointcut pointcut = new
StaticMethodMatcherPointcut() {
@Override
public boolean matches(Method method, Class<?> targetClass) {
return method.isAnnotationPresent(MyCheck.class);
}
};
@Override
public Pointcut getPointcut() {
return pointcut;
}
@Override
public Advice getAdvice() {
return myMethodInterceptor;
}
}
method interceptor
@Component
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
MyCheck annotation = methodInvocation.getMethod().getAnnotation(MyCheck.class);
if (mySpecialCheck(annotation.feature())) {
return methodInvocation.proceed();
}
return null;
}
}
It seems almost work. It works for object if the called method (that overrides parent interface) has correspond annotation. But it does not work for methods which overrides interface without annotation in case the interface methods has the annotation. See methods log()
and log3()
.
As for me there are two potential candidates into solution:
unfortunately i'm not strong in both of them.
You can traverse all the super classes and interfaces' super methods to find the annotation. But you may find more than one annotation because the method may declared in several classes or interfaces.
Here is my sample code:
public class Q46553516 {
public static void main(String[] args) throws Exception {
// the input method
Method method = ClassB.class.getMethod("func");
// get the annotation value
Class<?> clz = method.getDeclaringClass();
List<Anno> collect = Stream.concat(
Stream.of(clz),
Stream.concat(
Stream.of(ReflectUtil.getAllSuperClasses(clz)),
Stream.of(ReflectUtil.getAllInterfaces(clz))))
.map(c -> {
try {
return c.getMethod(method.getName(), method.getParameterTypes());
} catch (Exception e) {
return null;
}
})
.filter(m -> m != null)
.map(m -> m.getAnnotation(Anno.class))
.filter(a -> a != null)
.collect(Collectors.toList());
collect.forEach(System.out::println);
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
@Inherited
public @interface Anno {
String value();
}
static interface Inter {
@Anno("Inter")
void func();
}
static class ClassA implements Inter {
@Override
@Anno("ClassA")
public void func() {
}
}
static class ClassB extends ClassA {
@Override
public void func() {
}
}
}
and output:
@xdean.stackoverflow.java.reflection.Q46553516$MyCheck(feature=ClassA)
@xdean.stackoverflow.java.reflection.Q46553516$MyCheck(feature=Inter)
I used my utility ReflectUtil
, you can find it here