2017-03-05 48 views
3
接口和方法

效仿註釋繼承人們經常問的AspectJ類似這樣的問題,所以我想回答它在一個地方,我可以很容易地鏈接到更高版本。與AspectJ的

我有這個標記註釋:

package de.scrum_master.app; 

import java.lang.annotation.Inherited; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 

@Inherited 
@Retention(RetentionPolicy.RUNTIME) 
public @interface Marker {} 

現在我詮釋這樣的接口和/或方法:

package de.scrum_master.app; 

@Marker 
public interface MyInterface { 
    void one(); 
    @Marker void two(); 
} 

這裏是一個小驅動器應用程序,它也實現了接口:

現在,當我定義這方面,我希望它被觸發

  • 一個被註解類的每個構造函數執行和
  • 一個註解的方法的每次執行。
package de.scrum_master.aspect; 

import de.scrum_master.app.Marker; 

public aspect MarkerAnnotationInterceptor { 
    after() : execution((@Marker *).new(..)) && !within(MarkerAnnotationInterceptor) { 
    System.out.println(thisJoinPoint); 
    } 

    after() : execution(@Marker * *(..)) && !within(MarkerAnnotationInterceptor) { 
    System.out.println(thisJoinPoint); 
    } 
} 

不幸的是,一方面打印什麼,就好像類Application和方法two()沒有任何@Marker註解。 AspectJ爲什麼不攔截它們?

回答

3

這裏的問題不是AspectJ的,但JVM。在Java中,對

  • 接口註釋,
  • 方法或
  • 其他註釋

永遠不會被

  • 實現類繼承,
  • 覆蓋方法或
  • 使用帶註釋的註釋的類。

註釋繼承只能從類工程的子類,但只有在超使用的註釋類型熊元註解@Inherited,看到JDK JavaDoc

AspectJ是一個JVM的語言,因此JVM的限制範圍內工作。沒有針對此問題沒有通用的解決方案,但對於具體的接口或方法你想效仿註釋的繼承,你可以使用這樣一個解決方法:

package de.scrum_master.aspect; 

import de.scrum_master.app.Marker; 
import de.scrum_master.app.MyInterface; 

/** 
* It is a known JVM limitation that annotations are never inherited from interface 
* to implementing class or from method to overriding method, see explanation in 
* <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/annotation/Inherited.html">JDK API</a>. 
* <p> 
* Here is a little AspectJ trick which does it manually. 
* 
*/ 
public aspect MarkerAnnotationInheritor { 
    // Implementing classes should inherit marker annotation 
    declare @type: MyInterface+ : @Marker; 
    // Overriding methods 'two' should inherit marker annotation 
    declare @method : void MyInterface+.two() : @Marker; 
} 

請注意:在地方在這方面中,你因爲AspectJ的ITD(幀間類型定義)機制將它們添加回到接口加上所有執行/覆蓋類/方法可以從界面和批註的方法去除(文字)的註釋。

現在運行Application當控制檯日誌說:

execution(de.scrum_master.app.Application()) 
execution(void de.scrum_master.app.Application.two()) 

順便問一下,你也可以嵌入方面對入接口,從而在一個地方擁有的一切。只需要小心重命名MyInterface.javaMyInterface.aj以幫助AspectJ編譯器識別它必須在這裏做一些工作。

package de.scrum_master.app; 

public interface MyInterface { 
    void one(); 
    void two(); 

    public static aspect MarkerAnnotationInheritor { 
    // Implementing classes should inherit marker annotation 
    declare @type: MyInterface+ : @Marker; 
    // Overriding methods 'two' should inherit marker annotation 
    declare @method : void MyInterface+.two() : @Marker; 
    } 
} 
+0

謝謝。可以增強動態發現註釋的方法嗎? – NeilS

+0

@NeilS,我不明白這個問題。 – kriegaex

+0

在你的例子中,你的方面專門處理名爲'two'的方法。它具體到'兩',不可重用於其他情況。有沒有一種方法可以選擇任何已經使用某些註釋進行註釋的方法,而不是直接按名稱來提及它們? – NeilS