2010-12-08 5 views
28

JAXB를 배우기 시작 했으므로 내 질문이 매우 어리 석을 수 있습니다. 이제 클래스가 생겨서 XML 스키마를 생성하려고합니다. this 명령 후가는 나는 예외를JAXB 및 생성자

IllegalAnnotationExceptions ... 인수 없음의 기본 생성자가 없습니다를 얻을.

예. 내 클래스는 기본 인수가없는 생성자가 없습니다. 너무 쉽습니다. 나는 패키지를 볼 수있는 생성자/최종 메소드를 가진 클래스를 가지고 있으며, 인수를 가진 코스를 벗어난다. 어떻게해야합니까? 특정 momemto/builder 클래스를 만들거나 JAXB에 대한 생성자를 지정합니다 (어떤 방식으로?). 감사.

답변

42

JAXB는 XML 어댑터를 사용하여이 경우를 지원할 수 있습니다. 그들 사이의 변환

package blog.immutable.adpater; 

import javax.xml.bind.annotation.XmlAttribute; 
import blog.immutable.Address; 

public class AdaptedCustomer { 

    private String name; 
    private Address address; 

    @XmlAttribute 
    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    public Address getAddress() { 
     return address; 
    } 

    public void setAddress(Address address) { 
     this.address = address; 
    } 

} 

와 XML 어댑터 : 당신은 단순히이 클래스의 매핑 가능한 버전을 만들 필요가

package blog.immutable; 

public class Customer { 

    private final String name; 
    private final Address address; 

    public Customer(String name, Address address) { 
     this.name = name; 
     this.address = address; 
    } 

    public String getName() { 
     return name; 
    } 

    public Address getAddress() { 
     return address; 
    } 

} 

: 다음없이 제로 인수 생성자와 객체를 고려

: Customer 클래스를 참조 속성에 대한 다음
package blog.immutable.adpater; 

import javax.xml.bind.annotation.adapters.XmlAdapter; 
import blog.immutable.Customer; 

public class CustomerAdapter extends XmlAdapter<AdaptedCustomer, Customer> { 

    @Override 
    public Customer unmarshal(AdaptedCustomer adaptedCustomer) throws Exception { 
     return new Customer(adaptedCustomer.getName(), adaptedCustomer.getAddress()); 
    } 

    @Override 
    public AdaptedCustomer marshal(Customer customer) throws Exception { 
     AdaptedCustomer adaptedCustomer = new AdaptedCustomer(); 
     adaptedCustomer.setName(customer.getName()); 
     adaptedCustomer.setAddress(customer.getAddress()); 
     return adaptedCustomer; 
    } 

} 

, 단순히 @XmlJavaTypeAdapter 주석을 사용 더 자세한 예를 들어

package blog.immutable; 

import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 
import blog.immutable.adpater.CustomerAdapter; 

@XmlRootElement(name="purchase-order") 
public class PurchaseOrder { 

    private Customer customer; 

    @XmlJavaTypeAdapter(CustomerAdapter.class) 
    public Customer getCustomer() { 
     return customer; 
    } 

    public void setCustomer(Customer customer) { 
     this.customer = customer; 
    } 

} 

은 다음을 참조하십시오

+3

직접 링크를 복사하거나 답변의 기본 사항을 설명하지 말고 자세한 설명이 필요하면 블로그 게시물에 연결하십시오. 이렇게하면 링크가 죽어 버린 경우에도 답을 얻을 수 있습니다. –

+1

이것들은 내가 감사 할 필요가있는 것이다. –

+2

나는 단지 링크를 복사하는 것에 동의한다. 이 답변은 내 통근 중에 휴대 전화에서 작업하도록 게시되었습니다. 나는 컴퓨터에있을 때 더 자세한 정보를 제공 할 것이다. 그게 도움이된다면 내 블로그에 연결됩니다. –

5

클래스를 인스턴스화 할 수 있도록 JAXB에 대한 기본 생성자가 있어야합니다. 어쩌면 제가 모르는 해결 방법이있을 수 있습니다.

JAXB는 bean과 같은 클래스에 특히 적합하여 setter를 호출하여 객체를 구성 할 수 있습니다.

+1

모든 클래스에 대한 기본 생성자를 만드는 것은 매우 나쁜 생각입니다. 몇 가지 해결 방법이 있어야합니다. –

+0

그 디자인도 마음에 들지 않지만 표준 JAXB 방식입니다. – Guillaume

+0

솔직히 말해서 인과 관계가없는 인종 차별주의를 솔직하게 이해하지 못합니다.빈 클래스는 복잡한 초기화가있는 클래스가 아니라 XML로 쉽게 변형 될 수있는 정보 용 컨테이너 여야합니다. –

3

JAXB는 간단한 방식으로 XML에서 빈을 다시 작성합니다. 빈의 새 인스턴스를 작성한 다음 속성을 설정하는 데 필요한 모든 작업을 수행합니다. 그래서 bean이 args가없는 생성자를 가지지 않는다면, JAXB는 그것을 생성 할 수 없다. 다른 대답에서 말했듯이, JAXB는 인자없는 생성자가 실제로 문제가되지 않는 단순한 "컨테이너"빈에 대해 더 잘 작동합니다. 특정 초기화가 필요한 bean을 작성하려는 경우 setXXX 메소드에서 수행해야합니다.

+2

불변의 개체로 작업하기위한 연습이 필요하다고 생각합니다. 등등. –

+0

@Stas : Guillaume의 답변에 대한 내 의견을 참조하십시오. JAXB가 JAXB를 생성해야한다면, 변경할 수 없습니다. JAXB는 변경 불가능한 객체를 만드는 것이 아니라 나중에 정보를 취하는 "전송"객체를 만들기 위해 만들어졌습니다. –

+0

또는 public no-args 생성자가없는 경우 간단하게 두는 것은 bean이 아닙니다. 그건 javabean 사양의 일부입니다. –

13

당신은 주석 @XmlType을 사용하고 factoryMethod/factoryClass- 설정과 같은 다양한 조합으로 속성을 사용할 수 있습니다

@XmlType(factoryMethod="newInstance") 
@XmlRootElement 
public class PurchaseOrder { 
    @XmlElement 
    private final String address; 
    @XmlElement 
    private final Customer customer; 

    public PurchaseOrder(String address, Customer customer){ 
     this.address = address; 
     this.customer = customer; 
    } 

    private PurchaseOrder(){ 
     this.address = null; 
     this.customer = null; 
    } 
    /** Creates a new instance, will only be used by Jaxb. */ 
    public static PurchaseOrder newInstance() { 
     return new PurchaseOrder(); 
    } 

    public String getAddress() { 
     return address; 
    } 

    public Customer getCustomer() { 
     return customer; 
    } 
} 

놀랍게도이 기능은 d) 언 마샬링 할 때 초기화 된 인스턴스를 얻는다. 코드에서 유효하지 않은 인스턴스를 반환하기 때문에 newInstance 메서드를 호출하지 않도록주의해야합니다.

+0

정말 멋진 기능입니다. 나는 노력해야한다. –

+3

public 메서드를 만들면 JAXB뿐만 아니라 누구나 액세스 할 수있게되어 디자인 타임에 도입 된 필드에 대한 디자인 및 무효화 및 제약을 잠재적으로 손상시킬 수 있습니다. 나는이 해결책을 추천 할 수 없다! – Eric

+0

네, 저도 알고 있습니다.하지만 언제나 그렇듯이 단순성을 위해 무엇을 기꺼이 인정 하느냐에 달렸습니다. 모든 메서드에 대해 정의 된 인터페이스를 따라 재생할 수 있으므로 다른 유틸리티 메서드가 숨겨져 있지만 원래 포스터에서 무엇을 해결할 것인지 확실하지 않습니다. –