2010-12-08 9 views
28

私はJAXBの学習を始めているので、私の質問は非常にばかげている可能性があります。今私はクラスがあり、XMLスキーマを生成したい。私は例外JAXBとコンストラクタ

IllegalAnnotationExceptionsを取得this命令の後に行く...引数なしのデフォルトに コンストラクタを持っていません。

ええ。私のクラスはデフォルトの引数なしコンストラクタを持っていません。それは簡単すぎる。私はパッケージの可視コンストラクタ/最終的なメソッドを持つクラスを持っていて、引数を使ってコースから離れています。何をすればいいのですか?特定のmomemto/builderクラスを作成するか、JAXBへのコンストラクタを指定します(どのようにしてですか?)。ありがとう。

答えて

42

JAXBは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; 
    } 

} 

あなたは、単にこのクラスのマッピング可能なバージョンを作成する必要があります。

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アダプタ:

: 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のようなクラスに特に適しています。そのため、JAXBはsetterを呼び出してオブジェクトを構成することができます。

+1

すべてのクラスのデフォルトコンストラクタを作成することは非常に悪い考えです。いくつかの回避策が必要です。 –

+0

私はそのデザインも好きではありませんが、これは標準のJAXBの方法です... – Guillaume

+0

私は率直にも、引数なしの人種差別を本当に理解していません。Beanクラスは情報のコンテナである必要があります。複雑な初期化を持つクラスではなく、簡単にXMLに変換できます。 –

3

JAXBは簡単な方法でXMLからBeanを再作成します。つまり、Beanの新しいインスタンスを作成し、属性を設定するために必要なすべての操作を行います。したがって、あなたのBeanに引数なしのコンストラクタがない場合、JAXBはそれを作成できません。他の答えで言われているように、JAXBは単純な "コンテナ" beanの方がうまく動作しますが、argsのコンストラクタは本当に問題ではありません。特定の初期化が必要なBeanを作成しようとしている場合は、setXXXメソッドで行う必要があります。

+2

私は不変のオブジェクトを扱うためのいくつかの練習が必要であると思いますなど。 –

+0

@Stas:ギヨームの答えに私のコメントを参照してください。 JAXBが作成する必要がある場合、JAXBはそれを変更することはできません。 JAXBは、不変のオブジェクトを作成するためのものではなく、後から情報を取得するより多くの「移送」オブジェクトです。 –

+0

また、パブリック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; 
    } 
} 

驚いたことに、これはあなたは非整列時に初期化されたインスタンスを取得します。無効なインスタンスが返されるため、コードのどこでもnewInstanceメソッドを呼び出さないように注意してください。

+0

それは本当にクールなものです。私は試してみるべきです。 –

+3

パブリックメソッドを作成すると、JAXBだけでなく誰でもアクセスできるようになり、設計時に導入されたフィールドの設計や無効化や制約を潜在的に損なう可能性があります。私はこのソリューションをお勧めできません! – Eric

+0

はい、私はそれを認識していますが、いつものように、単純さのために何を譲りたいと思っているかによって決まります。あなたはあなたのすべてのメソッドのためのインターフェイスを定義しながらプレイすることができるので、他のユーティリティメソッドを隠していましたが、元のポスターが何を解決したいのか分かりません。 –