2011-12-17 3 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는 1 대신 2가됩니다. 코드를 디버깅 할 때 Digester는 생성자 매개 변수로 "null"을 가진 2 개의 추가 객체를 만들었습니다.

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

생성자의 인수가 null인지 확인하는 코드가 있으면 모든 종류의 문제가 발생합니다.

내 역할 클래스의 정의는 다음과 같습니다 ... 제가 질문 3 세입니다 참조

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

또한 매개 변수로 null로만 호출되는 내 개체 생성자 beeing에 문제가있는 동안 digester 3.2에서이 동작을 발견했습니다. 두 번 부르는 것이 정상적인 지 알았습니까? 또한 잘못된 매개 변수로 호출 된 생성자 beeing에 문제가 있습니까? – gsnerf

답변

0

하지만 최근에이 같은 일을 건너 온 대답은 여전히 ​​유효

생성자가 두 번 호출 된 이유는 Digester 3가 생성자를 매개 변수로 처리하는 방식입니다. Digester 문제는 닭고기와 계란 하나입니다 ... 모든 필수 매개 변수를 가질 때까지는 생성자를 호출 할 수 없지만 callParam 규칙은 자식 요소에서 데이터를 가져올 수 있기 때문에 모든 자식 요소가있을 때까지 모든 자식 요소를 가질 수 없습니다. 요소를 완전히 처리했습니다. 귀하의 경우에는

는, 모든 매개 변수는 속성에서 사용할 수 있습니다,하지만 당신은 당신의 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> 사이에서 발생하며 개체를 만들기 전에이 모든 작업을 수행해야합니다.

이렇게하기 위해 digester는 생성 될 클래스 (역할) 주위에 프록시 래퍼를 만들고, 모든 생성자 인수에 대해 null을 전달하는 더미 인스턴스를 만든 다음 main 요소의 하위에 대해 트리거 된 다른 모든 메서드를 호출합니다. 프록시 클래스는 이러한 메서드 호출을 가로 채고 매개 변수를 포함하여이를 기록하며 더미 인스턴스에 전달합니다. 끝 요소 태그에 도달하면 더미 객체는 삭제되고 실제 생성자 매개 변수로 새 객체가 만들어지고 기록 된 모든 메서드 호출이 새 객체로 다시 재생됩니다.

눈치 챘을 때, 이것은 객체를 두 번 생성 할뿐 아니라 다이제스트 규칙에 의해 트리거 된 모든 메서드를 '녹음'단계에서 한 번, '재생'단계에서 한 번 호출합니다.

이 모든 것이 단순한 데이터 개체에는 적합하지만보다 복잡한 데이터 개체를 만들 때는 이상한 결과가 발생할 수 있습니다. 예를 들어 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을 참조하십시오.

호프가이 수수께끼를 없애기를 바랍니다.

관련 문제