2011-04-27 23 views
2

我正在使用Aspectj進行項目範圍的策略執行。關於使用AspectJ進行策略執行

我現在想要實現的一件事是,除了用Guava的Preconditions.check*方法進行簡單驗證之外,任何setter方法都不應該有邏輯。

public pointcut withinSetter() : 
    withincode(public void set*(*)); 
public pointcut inputValidation() : 
    call(public void Preconditions.check*(*)); 
public pointcut setFieldValue() : set(* *); 
public pointcut entity() : within(com.mycompany.BaseEntity+); 

declare warning : 
entity() && withinSetter() && !setFieldValue() && !inputValidation(): 
"Please don't use Logic in Setters"; 

這可以按預期工作,爲任何非設置代碼生成警告。但是,它未能對這樣的結構:

public void setFoo(final String newFoo) { 
    Preconditions.checkNotNull(newFoo); // this is OK 
    Preconditions.checkArgument(
       newFoo.matches("\\p{Alpha}{3}"), // this generates a warning 
                // because String.matches() 
                // is called 
       "Foo must have exactly 3 characters!"); 
    this.foo = newFoo; 
} 

所以我所尋找的是一個結構,它允許任何代碼,只要它發生在裏面的參數爲Preconditions.check*電話。有沒有這樣的切入點?

+3

我不認爲你可以。即使你可以,有人可以在「Preconditions」調用中潛入一個改變狀態的呼叫。白名單允許的方法是什麼?那裏有很多嗎? – Rom1 2011-04-27 14:02:13

+0

@ Rom1偷偷摸摸:我意識到這一點,但願意承擔風險。我正在反對壞習慣,而不是反對邪惡的黑客。白名單:這就是我目前正在做的事情。問題是這是一個有很多不同編碼風格的大項目:-) – 2011-04-27 14:21:02

回答

1

我知道這是一個古老的問題,但我在尋找別的東西時偶然發現了它。

答案是否定的,因爲在JVM字節碼中不存在「check*調用中的邏輯」之類的東西。

boolean match = newFoo.matches("\\p{Alpha}{3}"); 
Preconditions.checkArgument(match, "Foo must have exactly 3 characters!"); 

如果代碼是這樣寫的,你會發出警告安韋,那麼爲什麼不若:例如,newFoo.matches(..)之前結果傳遞到Preconditions.checkArgument(..),非常喜歡這個評估相同的Java代碼,可能導致類似或相同的字節代碼,被寫爲嵌套調用? ;-)


更新:我創建了一個小例子:

public class Application { 
    public static void main(String[] args) { 
     String newFoo = "Scrum"; 
     boolean match = newFoo.matches("\\p{Alpha}{3}"); 
     checkArgument(
      match, 
      "Foo must have exactly 3 characters!" 
     ); 
     checkArgument(
      newFoo.matches("\\p{Alpha}{3}"), 
      "Foo must have exactly 3 characters!" 
     ); 
    } 

    private static void checkArgument(boolean status, String errorMessage) { 
     if (!status) 
      System.out.println(errorMessage); 
    } 
} 

如果您轉儲使用javap -c Application字節代碼,你看到這一點:

Compiled from "Application.java" 
public class Application extends java.lang.Object{ 
public Application(); 
    Code: 
    0: aload_0 
    1: invokespecial #8; //Method java/lang/Object."<init>":()V 
    4: return 

public static void main(java.lang.String[]); 
    Code: 
    0: ldC#16; //String Scrum 
    2: astore_1 
    3: aload_1 
    4: ldC#18; //String \p{Alpha}{3} 
    6: invokevirtual #20; //Method java/lang/String.matches:(Ljava/lang/String;)Z 
    9: istore_2 
    10: iload_2 
    11: ldC#26; //String Foo must have exactly 3 characters! 
    13: invokestatic #28; //Method checkArgument:(ZLjava/lang/String;)V 
    16: aload_1 
    17: ldC#18; //String \p{Alpha}{3} 
    19: invokevirtual #20; //Method java/lang/String.matches:(Ljava/lang/String;)Z 
    22: ldC#26; //String Foo must have exactly 3 characters! 
    24: invokestatic #28; //Method checkArgument:(ZLjava/lang/String;)V 
    27: return 

} 

正如你所看到的,除了存儲和重新加載布爾值之外,轉儲中行3-13與16-24的字節代碼是相同的。也許這說明了我之前說過的話。

+0

謝謝。我已經算了很多。 – 2013-08-12 07:46:15