2011-06-09 54 views
2

我們一直通過將大部分構造函數代碼移動到onInitialize()來避免此PMD警告。但是,我們只是將問題(設計缺陷?)轉移到一個不同的地方?Wicket和'構造函數調用可重寫的方法'PMD警告

即我們的onInitialize()只是一個代理構造函數,它不被PMD注意到嗎?

我們遇到了在構造函數中調用可重寫方法時彈出的類的問題,但這似乎源於Wicket自己調用它的事實(找不到確切的源代碼行,但是onInitialize(),當您在構造函數中調用add()時,最終會被調用)。

如果能提供幫助,很樂意提供示例代碼。

public class PageA extends WebPage { 

    protected SomeBean bean; 

    public PageA() { 
     add(new Label("foo", "bar")); 
     bean = new SomeBean(); 
    } 

} 

public class PageB extends PageA { 

    public PageB() { 
     super(); 
    } 

    @Override 
    protected void onInitialize() { 
     add(new Label("rofl", bean.getSomeText())); 
    } 
} 

你可能會認爲這是好的,但在調用onInitialize不會發生,你可能會認爲它的作用:

當調用一個頁面上add()的方法流程爲:

MarkupContainer add()  
MarkupContainer addedComponent() 
Page    componentAdded() 
MarkupContainer initialize() 
Component   fireInitialize() 
Component   onInitialize() 

因此,您可以看到如果將組件添加到WebPage,則會觸發onInitialize()方法,這是一種可覆蓋的方法,可導致上述看起來正常的代碼創建NullPointerException s的實例。

唯一的警告你,這可能發生是onInitialize()的JavaDoc:

注意:此通話的時間是不準確的,合同是,它是{@link之前有時稱爲組件#onBeforeRender()}。

+0

是的,對我來說這聽起來像是一個設計缺陷。儘管如此,它還是很好的提供一些具體的東西。 – 2011-06-09 11:04:56

+2

另請參見:http://stackoverflow.com/questions/4914151 – 2011-06-09 11:14:36

+2

如果您閱讀Wicket論壇(http://apache-wicket.1842946.n4.nabble.com/VOTE-WICKET-3218-Component-onInitialize- is-broken-for-Pages-tc3341090.html#none),你會發現這是一個公認和爭論的問題。 – jbrookover 2011-06-10 13:41:26

回答

4

如果您只是從其onInitialized()方法中將組件添加到容器中,則不會出現此問題。但它不能由PMD驗證,至少不能由內置規則驗證。

我不認爲這是一個設計瑕疵,但。這是一個設計決定。您無法將所有設計都基於靜態分析工具和預定義的規則。 API可用性也是設計的一個重要方面,有時甚至比設計原則更相關。

例如,CQS (Command-Query Separation)原則會強制要求該東西(改變狀態)的方法不應該返回任何東西,那返回什麼方法不應該有任何的副作用(改變狀態)。

如果這是一條硬性規則,流暢的接口(改變對象狀態的方法,並返回this,允許方法鏈接)無法實現。 Wicket廣泛使用它(幾乎所有的組件操作方法都會返回this),這是使它使用起來很愉快的事情之一。

PMD是一個非常有用的工具。但是你必須是工具的主人,而不是奴隸。您應該將其警告視爲可能的問題,但如果您對自己的設計選擇充滿信心,只需將代碼標記爲繞過並感到高興。

1

考慮下面的類:

public class A { 

    public A() { 
     System.out.println(val().toString()); 
    } 

    protected Integer val() { 
     return 0; 
    } 

} 

它看起來不錯乍一看,假設val()應該不會返回null,這是如此。現在BA

public class B extends A { 

    private final Integer i; 

    public B() { 
     //super(); //implicit 
     i = 1; 
    } 

    @Override 
    protected Integer val() { 
     return i; 
    } 
} 

B是一見鍾情罰款以及 - 它返回從val()這是從來沒有null因爲它final它在構造函數初始化i。但創建B實例將拋出NullPointerException。你能明白爲什麼嗎? 提示:看哪裏隱含super()發生。

你覺得移動i初始化會有幫助嗎?爲什麼不?

private final Integer i = 1; 

作爲一個經驗法則,永遠不要從非final類的構造函數中調用非私有方法。事實上,我甚至會在這種情況下觸發編譯錯誤。正如你可以看到這個問題與Wicket無關,移動初始化到onInitialize()是爲了避免這種陷阱。

+0

嗨,感謝您的回答和評論中的有用鏈接,但我已經明白爲什麼在構造函數中調用可重寫方法是不好的。我正在嘗試確定鏈接onInitialize調用是否會導致相同的問題。 – artbristol 2011-06-09 12:43:44

+0

當然,將它移出到一個單獨的方法違反了另一個原則,即在構建之後,對象必須始終處於一致狀態,並且其方法必須以任何順序調用,而不會失敗。 – biziclop 2011-06-09 13:00:37

0

當您在構造函數中調用overridable方法時彈出類型的問題,但似乎源於Wicket本身調用它的事實(無法找到確切的源代碼行,但onInitialize ()是一個可重寫的方法,當你在構造函數中調用add()時,結果會被調用。

我敢肯定的onInitialize()方法,當你調用add(component)這被稱爲是組件的onInitialize()方法添加(該參數add方法),而不是你目前正在建設之類的。這應該沒問題,因爲該組件已經完全構建。

+0

請參閱示例代碼,以瞭解如何在調用'add'之後獲得'onInitialized'。 – artbristol 2011-06-09 13:42:57

相關問題