2011-12-17 121 views
4

在Digester中存在一種奇怪的行爲,我無法包裹頭部。Digester 3在創建對象時調用構造函數兩次

我有下面的代碼調用時,它遇到「角色/角色」,在輸入XML節點「角色」對象的構造函數:

 AbstractRulesModule loader = (new AbstractRulesModule() { 

     protected void configure() { 
      forPattern("roles/role").createObject().ofType(Role.class) 
        .usingConstructor(String.class, String.class).then() 
        .callParam().fromAttribute("machine").ofIndex(0); 

      forPattern("roles/role").callParam().fromAttribute("name") 
        .ofIndex(1); 

      forPattern("roles/role").setNext("add"); 

     } 
    }); 

    Digester digester = DigesterLoader.newLoader(loader).newDigester(); 
    List<Role> roles = new ArrayList<>(); 

    digester.push(roles); 

    digester.parse(new File("c:/RoleMapping.xml")); 

    System.out.println(roles); 
    System.out.println(Role.count); 

每一次角色的構造函數被調用,Role.count遞增。奇怪的是,在針對以下xml運行上述代碼之後,Role.count是2而不是1.當我調試代碼時,Digester似乎試圖創建2個額外的帶有「null」作爲構造參數的對象。

<roles> 
    <role name="m1" machine="mymachine" /> 
</roles> 

這將導致各種問題,如果我有代碼檢查,如果構造函數的參數爲​​null。

我的角色類的定義是:

public class Role { 

    private String machine; 
    private String name; 

    static int count = 0; 

    public Role(String machine, String name) { 
     this.machine = machine; 
     this.name = name; 
     count++; 
    } 
} 
+0

我也注意到這與消化器3.2的行爲,同時試圖繞過一些問題與我的對象構造函數beeing只調用null作爲參數。你有沒有發現是否調用兩次是正常的?你有沒有問題與你的構造函數調用錯誤的參數? – gsnerf 2013-10-29 13:28:32

回答

0

我看到的問題是,3歲,但我最近碰到同樣的事情來了,答案仍然是有效的...

的因爲構造函數被調用兩次是因爲Digester 3使用參數處理構造函數。 Digester的問題是雞和蛋......它不能調用構造函數直到它具有所有必需的參數,但因爲規則可以從子元素獲取它們的數據,所以它不具有所有子元素,直到它具有完全處理元素。

在你的情況,所有的參數都在屬性可用,但考慮,如果你改變了你的XML:

<roles> 
    <role> 
     <name>m1</name> 
     <machine>mymachine</machine> 
    </role> 
</roles> 

甚至:

<roles> 
    <role> 
     <name>m1</name> 
     <machine>mymachine</machine> 
     <another> 
      <tag>which</tag> 
      <does>morestuff</does> 
      ... 
     </another> 
    </role> 
</roles> 

消化器有效必須記住一切發生在<role></role>之間,因爲可以在子數據中的任何位置調用調用參數規則,並且必須在創建對象之前完成所有這些操作。

要做到這一點,沼氣工程創建一個圍繞要構造的類的代理包裝(Role),創建一個爲所有構造函數參數傳遞null的虛擬實例,然後調用爲主要元素的子項觸發的所有其他方法。代理類攔截這些方法調用,記錄它們(包括參數),並將它們傳遞給虛擬實例。一旦達到了end元素標籤,虛擬對象就會被丟棄,一個新的構造函數參數被創建,並且所有記錄的方法調用都被「重放」回新對象。你已經注意到,這不僅創建了兩次對象,而且還調用了由消化器規則兩次觸發的所有方法:一次在「錄製」階段,一次在「回放」階段。

這對所有簡單的數據對象都適用,但在構建更復雜的數據對象時可能會產生奇怪的後果。一個例子見this digester ticket

爲了只是避免空指針異常,你可以告訴哪些值使用usingDefaultConstructorArguments規則使用默認的構造函數參數沼氣池:

forPattern("roles/role").createObject().ofType(Role.class) 
    .usingConstructor(String.class, String.class).then() 
    .usingDefaultConstructorArguments("one", "two").then() 
    .callParam().fromAttribute("machine").ofIndex(0); 

對於更復雜的情況下,或只是如果你喜歡的方式,你可以使用構建器類和自定義規則。基本思想是當你到達將構建器類推入堆棧的元素以及元素結束標記上觸發的自定義規則時。在處理元素體時,消化器將所有規則調用爲正常將數據傳遞給構建器類。在結束標記處,會觸發自定義規則,調用構建器來構建對象,然後用構建的對象替換蒸煮器堆棧上的構建器對象。這確實需要一個自定義的構建器類,但比聽起來簡單得多。有關工作示例,請參見this digester ticket

希望這清除了神祕!

相關問題