XStreamユーザーガイド:オブジェクトをXMLに変換

XStreamユーザーガイド:オブジェクトのXMLへの変換

1. 概要

このチュートリアルでは、XStreamライブラリを使用してJavaオブジェクトをXMLにシリアル化する方法を学習します。

2. 特徴

XStreamを使用してXMLをシリアル化および逆シリアル化することには、いくつかの興味深い利点があります。

  • 適切に構成すると、非常にclean XMLが生成​​されます

  • XML出力のcustomizationに重要な機会を提供します

  • 循環参照を含むobject graphsのサポート

  • ほとんどのユースケースでは、XStreamインスタンスはthread-safe, once configuredです(アノテーションを使用する場合は注意が必要です)

  • 問題の診断に役立つ明確なメッセージがexception handlingの間に提供されます

  • バージョン1.4.7以降、特定のタイプのシリアル化を禁止するためにsecurity featuresを使用できるようになりました

3. プロジェクトのセットアップ

プロジェクトでXStreamを使用するには、次のMaven依存関係を追加します。


    com.thoughtworks.xstream
    xstream
    1.4.9

4. 基本的な使い方

XStreamクラスは、APIのファサードです。 XStreamのインスタンスを作成するときは、スレッドセーフの問題にも注意を払う必要があります。

XStream xstream = new XStream();

インスタンスが作成および設定されると、注釈処理を有効にしない限り、マーシャリング/アンマーシャリングのために複数のスレッドで共有される場合があります。

4.1. 運転者

DomDriverStaxDriverXppDriverなどのいくつかのドライバーがサポートされています。 これらのドライバーには、異なるパフォーマンスとリソースの使用特性があります。

XPP3ドライバーはデフォルトで使用されますが、もちろんドライバーを簡単に変更できます。

XStream xstream = new XStream(new StaxDriver());

4.2. XMLの生成

Customerの単純なPOJOを定義することから始めましょう。

public class Customer {

    private String firstName;
    private String lastName;
    private Date dob;

    // standard constructor, setters, and getters
}

次に、オブジェクトのXML表現を生成しましょう。

Customer customer = new Customer("John", "Doe", new Date());
String dataXml = xstream.toXML(customer);

デフォルト設定を使用すると、次の出力が生成されます。


    John
    Doe
    1986-02-14 03:46:16.381 UTC

この出力から、含まれているタグがデフォルトでCustomerの完全修飾クラス名を使用していることがはっきりとわかります.

デフォルトの動作がニーズに合わないと判断する理由はたくさんあります。 たとえば、アプリケーションのパッケージ構造を公開するのは不安かもしれません。 また、生成されるXMLは大幅に長くなります。

5. エイリアス

aliasは、デフォルトの名前ではなく、要素に使用する名前です。

たとえば、Customerクラスのエイリアスを登録することで、com.example.pojo.Customercustomerに置き換えることができます。 クラスのプロパティのエイリアスを追加することもできます。 エイリアスを使用することで、XML出力をはるかに読みやすく、Java固有のものを少なくすることができます。

5.1. クラスエイリアス

エイリアスは、プログラムで、または注釈を使用して登録できます。

ここで、Customerクラスに@XStreamAliasアノテーションを付けましょう。

@XStreamAlias("customer")

次に、この注釈を使用するようにインスタンスを構成する必要があります。

xstream.processAnnotations(Customer.class);

または、プログラムでエイリアスを設定する場合は、次のコードを使用できます。

xstream.alias("customer", Customer.class);

エイリアス構成とプログラム構成のどちらを使用する場合でも、Customerオブジェクトの出力ははるかにクリーンになります。


    John
    Doe
    1986-02-14 03:46:16.381 UTC

5.2. フィールドエイリアス

クラスのエイリアスに使用されるのと同じ注釈を使用して、フィールドのエイリアスを追加することもできます。 たとえば、XML表現でフィールドfirstNamefnに置き換えたい場合は、次のアノテーションを使用できます。

@XStreamAlias("fn")
private String firstName;

または、同じ目標をプログラムで達成することもできます。

xstream.aliasField("fn", Customer.class, "firstName");

aliasFieldメソッドは、使用するエイリアス、プロパティが定義されているクラス、エイリアスするプロパティ名の3つの引数を受け入れます。

どちらの方法を使用しても、出力は同じです。


    John
    Doe
    1986-02-14 03:46:16.381 UTC

5.3. デフォルトのエイリアス

クラス用に事前登録されたエイリアスがいくつかあります。これらのいくつかを次に示します。

alias("float", Float.class);
alias("date", Date.class);
alias("gregorian-calendar", Calendar.class);
alias("url", URL.class);
alias("list", List.class);
alias("locale", Locale.class);
alias("currency", Currency.class);

6. コレクション

次に、Customerクラス内にContactDetailsのリストを追加します。

private List contactDetailsList;

コレクション処理のデフォルト設定では、これは出力です。


    John
    Doe
    1986-02-14 04:14:05.874 UTC
    
        
            6673543265
            0124-2460311
        
        
            4676543565
            0120-223312
        
    

contactDetailsListの親タグ,を省略する必要があり、各ContactDetails要素をcustomer要素の子にしたい場合を考えてみましょう。 例をもう一度変更しましょう。

xstream.addImplicitCollection(Customer.class, "contactDetailsList");

これで、XMLが生成されるときに、ルートタグが省略され、次のXMLになります。


    John
    Doe
    1986-02-14 04:14:20.541 UTC
    
        6673543265
        0124-2460311
    
    
        4676543565
        0120-223312
    

アノテーションを使用しても同じことが実現できます。

@XStreamImplicit
private List contactDetailsList;

7. コンバーター

XStreamは、Converterインスタンスのマップを使用し、それぞれに独自の変換戦略があります。 これらは、提供されたデータをXMLの特定の形式に変換し、再び元に戻します。

デフォルトのコンバーターを使用することに加えて、デフォルトを変更したり、カスタムコンバーターを登録したりできます。

7.1. 既存のコンバーターの変更

XStream(DateConverter)によって提供される_ using the default settings. We can modify the custom converter for _Dateタグが生成される方法に満足できなかったとします。

xstream.registerConverter(new DateConverter("dd-MM-yyyy", null));

上記は、「dd-MM-yyyy」形式で出力を生成します。


    John
    Doe
    14-02-1986

7.2. カスタムコンバーター

また、前のセクションと同じ出力を実現するカスタムコンバーターを作成することもできます。

public class MyDateConverter implements Converter {

    private SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");

    @Override
    public boolean canConvert(Class clazz) {
        return Date.class.isAssignableFrom(clazz);
    }

    @Override
    public void marshal(
      Object value, HierarchicalStreamWriter writer, MarshallingContext arg2) {
        Date date = (Date)value;
        writer.setValue(formatter.format(date));
    }

    // other methods
}

最後に、MyDateConverterクラスを次のように登録します。

xstream.registerConverter(new MyDateConverter());

オブジェクトを文字列に変換するように設計されたSingleValueConverterインターフェイスを実装するコンバーターを作成することもできます。

public class MySingleValueConverter implements SingleValueConverter {

    @Override
    public boolean canConvert(Class clazz) {
        return Customer.class.isAssignableFrom(clazz);
    }

    @Override
    public String toString(Object obj) {
        SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
        Date date = ((Customer) obj).getDob();
        return ((Customer) obj).getFirstName() + ","
          + ((Customer) obj).getLastName() + ","
          + formatter.format(date);
    }

    // other methods
}

最後に、MySingleValueConverterを登録します。

xstream.registerConverter(new MySingleValueConverter());

MySingleValueConverterを使用すると、CustomerのXML出力は次のようになります。

John,Doe,14-02-1986

7.3. コンバーターの優先順位

Converterオブジェクトを登録するときに、それらの優先度レベルを設定することもできます。

XStream javadocsから:

コンバーターは、明示的な優先順位で登録できます。 デフォルトでは、XStream.PRIORITY_NORMALに登録されています。 同じ優先順位のコンバーターは、登録された逆の順序で使用されます。 デフォルトのコンバーター、つまり 他に登録されているコンバータが適切でない場合に使用されるコンバータは、優先度XStream.PRIORITY_VERY_LOWで登録できます。 XStreamは、デフォルトでReflectionConverterをフォールバックコンバーターとして使用します。

APIは、いくつかの名前付き優先度値を提供します。**

private static final int PRIORITY_NORMAL = 0;
private static final int PRIORITY_LOW = -10;
private static final int PRIORITY_VERY_LOW = -20;

8. フィールドの省略

注釈またはプログラム構成を使用して、生成されたXMLからフィールドを省略できます。 注釈を使用してフィールドを省略するには、問題のフィールドに@XStreamOmitField注釈を適用するだけです。

@XStreamOmitField
private String firstName;

プログラムでフィールドを省略するには、次の方法を使用します。

xstream.omitField(Customer.class, "firstName");

どちらの方法を選択しても、出力は同じです。


    Doe
    14-02-1986

9. 属性フィールド

要素自体ではなく、要素の属性としてフィールドをシリアル化したい場合があります。 contactTypeフィールドを追加するとします。

private String contactType;

contactTypeをXML属性として設定する場合は、@XStreamAsAttributeアノテーションを使用できます。

@XStreamAsAttribute
private String contactType;

または、同じ目標をプログラムで達成することもできます。

xstream.useAttributeFor(ContactDetails.class, "contactType");

上記のいずれの方法の出力も同じです。


    6673543265
    0124-2460311

10. 並行性

XStreamの処理モデルにはいくつかの課題があります。 インスタンスを構成すると、スレッドセーフになります。

注釈の処理は、マーシャリング/アンマーシャリングの直前に構成を変更することに注意することが重要です。 そのため、アノテーションを使用してインスタンスをオンザフライで構成する必要がある場合は、通常、スレッドごとに個別のXStreamインスタンスを使用することをお勧めします。

11. 結論

この記事では、XStreamを使用してオブジェクトをXMLに変換する基本について説明しました。 また、XML出力がニーズを満たすようにするために使用できるカスタマイズについても学びました。 最後に、注釈に関するスレッドセーフの問題を調べました。

このシリーズの次回の記事では、XMLをJavaオブジェクトに戻す方法について学びます。

この記事の完全なソースコードは、リンクされたGitHub repositoryからダウンロードできます。