2017-10-03 6 views
1

J'ai une interface:Comment obtenir des annotations de la méthode parent?

public interface JustToCheckInterface { 

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

    void log2(); 

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

et mise en œuvre:

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

J'ai créé l'annotation (l'un est utilisé dans mon interface et dans le composant de ressort):

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

    @Required 
    String feature(); 
} 

et conseiller:

@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; 
    } 
} 
méthode

intercepteurs

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

Il semble fonctionner presque. Cela fonctionne pour l'objet si la méthode appelée (qui remplace l'interface parent) a des annotations correspondantes. Mais cela ne fonctionne pas pour les méthodes qui remplacent l'interface sans annotation dans le cas où les méthodes d'interface ont l'annotation. Voir les méthodes log() et log3().

Quant à moi, il y a deux candidats potentiels en solution:

  • solution de réflexion (et obtenir superMethods annotations de super);
  • solution d'intercepteur (améliorer un).

Malheureusement je ne suis pas fort dans les deux.

Répondre

1

Vous pouvez parcourir toutes les super-classes et les super-méthodes des interfaces pour trouver l'annotation. Mais vous pouvez trouver plus d'une annotation car la méthode peut être déclarée dans plusieurs classes ou interfaces.

Voici mon exemple de 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() { 

    } 
    } 
} 

et sortie:

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

J'ai utilisé mon utilitaire ReflectUtil, vous pouvez le trouver here