如何从父方法获取注释?

时间:2017-10-03 21:13:11

标签: java spring reflection annotations aop

我有一个界面:

public interface JustToCheckInterface {

    @MyCheck(feature = "occurrence-logging")
    void log();

    void log2();

    @MyCheck(feature = "check-logging")
    void log3();
}

和实施:

@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");
    }
}

我已经创建了注释(我的界面和spring组件中使用了注释):

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Documented
public @interface MyCheck {

    @Required
    String feature();
}

和顾问:

@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;
    }
}

方法拦截器

@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;
    }
}

看起来几乎可行。如果被调用的方法(覆盖父接口)具有对应的注释,则它适用于对象。但是对于在接口方法具有注释的情况下覆盖没有注释的接口的方法,它不起作用。请参阅方法log()log3()

至于我,有两个潜在的候选人可以解决:

  • 反射解决方案(从super获取superMethods和注释);
  • 拦截器解决方案(改进一个)。
不幸的是,我对他们两个都不强。

1 个答案:

答案 0 :(得分:2)

您可以遍历所有超类和接口&#39;查找注释的超级方法。但是您可能会找到多个注释,因为该方法可能在多个类或接口中声明。

以下是我的示例代码:

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() {

    }
  }
}

并输出:

@xdean.stackoverflow.java.reflection.Q46553516$MyCheck(feature=ClassA)
@xdean.stackoverflow.java.reflection.Q46553516$MyCheck(feature=Inter)

我使用了我的实用程序ReflectUtil,您可以找到它here