1. 概要

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

2. 特徴

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

  • 適切に構成すると、非常にクリーンなXMLが生成されます。
  • XML出力のカスタマイズに重要な機会を提供します
  • 循環参照を含むオブジェクトグラフのサポート
  • ほとんどのユースケースでは、XStreamインスタンスはスレッドセーフであり、一度構成されると(アノテーションを使用する場合は注意が必要です)
  • 例外処理中に、問題の診断に役立つ明確なメッセージが提供されます
  • バージョン1.4.7以降、特定のタイプのシリアル化を禁止するためにセキュリティ機能を利用できるようになりました

3. プロジェクトの設定

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

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.4.18</version>
</dependency>

4. 基本的な使用法

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

XStream xstream = new XStream();

インスタンスが作成および構成されると、アノテーション処理を有効にしない限り、マーシャリング/アンマーシャリングのために複数のスレッド間でインスタンスを共有できます。

4.1. 運転手

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

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);

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

<com.baeldung.pojo.Customer>
    <firstName>John</firstName>
    <lastName>Doe</lastName>
    <dob>1986-02-14 03:46:16.381 UTC</dob>
</com.baeldung.pojo.Customer>

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

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

5. エイリアス

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

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

5.1. クラスエイリアス

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

次に、Customerクラスに@XStreamAliasで注釈を付けましょう。

@XStreamAlias("customer")

次に、このアノテーションを使用するようにインスタンスを構成する必要があります。

xstream.processAnnotations(Customer.class);

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

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

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

<customer>
    <firstName>John</firstName>
    <lastName>Doe</lastName>
    <dob>1986-02-14 03:46:16.381 UTC</dob>
</customer>

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

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

@XStreamAlias("fn")
private String firstName;

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

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

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

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

<customer>
    <fn>John</fn>
    <lastName>Doe</lastName>
    <dob>1986-02-14 03:46:16.381 UTC</dob>
</customer>

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<ContactDetails> contactDetailsList;

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

<customer>
    <firstName>John</firstName>
    <lastName>Doe</lastName>
    <dob>1986-02-14 04:14:05.874 UTC</dob>
    <contactDetailsList>
        <ContactDetails>
            <mobile>6673543265</mobile>
            <landline>0124-2460311</landline>
        </ContactDetails>
        <ContactDetails>
            <mobile>4676543565</mobile>
            <landline>0120-223312</landline>
        </ContactDetails>
    </contactDetailsList>
</customer>

contactDetailsList parent tags を省略し、各ContactDetails要素をcustomer要素の子にする必要があるとします。 。 例をもう一度変更してみましょう。

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

Now, when the XML is generated, the root tags are omitted, resulting in the XML below:

<customer>
    <firstName>John</firstName>
    <lastName>Doe</lastName>
    <dob>1986-02-14 04:14:20.541 UTC</dob>
    <ContactDetails>
        <mobile>6673543265</mobile>
        <landline>0124-2460311</landline>
    </ContactDetails>
    <ContactDetails>
        <mobile>4676543565</mobile>
        <landline>0120-223312</landline>
    </ContactDetails>
</customer>

同じことは、注釈を使用して実現することもできます。

@XStreamImplicit
private List<ContactDetails> contactDetailsList;

7. コンバーター

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

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

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

dobタグがデフォルト設定を使用して生成された方法に満足できなかったとします。 XStream( DateConverter )によって提供されるDateのカスタムコンバーターを変更できます。

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

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

<customer>
    <firstName>John</firstName>
    <lastName>Doe</lastName>
    <dob>14-02-1986</dob>
</customer>

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出力は次のようになります。

<customer>John,Doe,14-02-1986</customer>

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");

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

<customer> 
    <lastName>Doe</lastName> 
    <dob>14-02-1986</dob> 
</customer>

9. 属性フィールド

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

private String contactType;

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

@XStreamAsAttribute
private String contactType;

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

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

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

<ContactDetails contactType="Office">
    <mobile>6673543265</mobile>
    <landline>0124-2460311</landline>
</ContactDetails>

10. 並行性

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

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

11. 結論

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

このシリーズの次の記事では、XMLをJavaオブジェクトに変換する方法について学習します。

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