XML アイテムリーダーとライター
Spring Batch は、XML レコードの読み取りとそれらの Java オブジェクトへのマッピング、および Java オブジェクトを XML レコードとして書き込むためのトランザクションインフラストラクチャを提供します。
ストリーミング XML の制約 他の標準 XML 解析 API はバッチ処理要件に適合しないため、StAX API は I/O に使用されます(DOM は入力全体を一度にメモリにロードし、SAX はユーザーがコールバックのみを提供できるようにすることで解析プロセスを制御します)。 |
Spring Batch で XML の入出力がどのように機能するかを考慮する必要があります。まず、ファイルの読み取りや書き込みとは異なるが、Spring Batch XML 処理全体で共通する概念がいくつかあります。XML 処理では、トークン化する必要があるレコードの行(FieldSet
インスタンス)の代わりに、次の図に示すように、XML リソースは個々のレコードに対応する「フラグメント」のコレクションであると想定されます。
上記のシナリオでは、"trade" タグは「ルート要素」として定義されています。"<trade>" と "</trade>" の間にあるすべてが 1 つの「フラグメント」と見なされます。Spring Batch は、フラグメントをオブジェクトにバインドするためにオブジェクト /XML マッピング (OXM) を使用します。ただし、Spring Batch は特定の XML バインディングテクノロジに縛られていません。一般的な使用方法は、最も一般的な OXM テクノロジの統一された抽象化を提供する Spring OXM に委譲することです。Spring OXM への依存はオプションであり、必要に応じて Spring Batch 固有のインターフェースを実装することもできます。OXM がサポートするテクノロジとの関連を次の図に示します。
OXM の概要と、XML フラグメントを使用してレコードを表現する方法を使用して、リーダーとライターをさらに詳しく調べることができます。
StaxEventItemReader
StaxEventItemReader
構成は、XML 入力ストリームからのレコードを処理するための一般的なセットアップを提供します。まず、StaxEventItemReader
が処理できる次の XML レコードのセットを検討します。
<?xml version="1.0" encoding="UTF-8"?>
<records>
<trade xmlns="https://springframework.org/batch/sample/io/oxm/domain">
<isin>XYZ0001</isin>
<quantity>5</quantity>
<price>11.39</price>
<customer>Customer1</customer>
</trade>
<trade xmlns="https://springframework.org/batch/sample/io/oxm/domain">
<isin>XYZ0002</isin>
<quantity>2</quantity>
<price>72.99</price>
<customer>Customer2c</customer>
</trade>
<trade xmlns="https://springframework.org/batch/sample/io/oxm/domain">
<isin>XYZ0003</isin>
<quantity>9</quantity>
<price>99.99</price>
<customer>Customer3</customer>
</trade>
</records>
XML レコードを処理できるようにするには、次のものが必要です。
ルート要素名: マップされるオブジェクトを構成するフラグメントのルート要素の名前。構成例は、トレードの価値でこれを示しています。
リソース: 読み取るファイルを表す Spring リソース。
Unmarshaller
: XML フラグメントをオブジェクトにマッピングするために Spring OXM によって提供されるアンマーシャリング機能。
Java
XML
次の例は、trade
という名前のルート要素、data/iosample/input/input.xml
のリソース、Java で tradeMarshaller
と呼ばれるアンマーシャラーと連携する StaxEventItemReader
を定義する方法を示しています。
@Bean
public StaxEventItemReader itemReader() {
return new StaxEventItemReaderBuilder<Trade>()
.name("itemReader")
.resource(new FileSystemResource("org/springframework/batch/item/xml/domain/trades.xml"))
.addFragmentRootElements("trade")
.unmarshaller(tradeMarshaller())
.build();
}
次の例は、trade
という名前のルート要素、data/iosample/input/input.xml
のリソース、XML で tradeMarshaller
と呼ばれるアンマーシャラーと連携する StaxEventItemReader
を定義する方法を示しています。
<bean id="itemReader" class="org.springframework.batch.item.xml.StaxEventItemReader">
<property name="fragmentRootElementName" value="trade" />
<property name="resource" value="org/springframework/batch/item/xml/domain/trades.xml" />
<property name="unmarshaller" ref="tradeMarshaller" />
</bean>
この例では、XStreamMarshaller
を使用することを選択したことに注意してください。これは、マップとして渡されたエイリアスを受け入れ、最初のキーと値はフラグメントの名前(つまり、ルート要素)とバインドするオブジェクト型です。次に、FieldSet
と同様に、オブジェクト型内のフィールドにマップされる他の要素の名前は、マップ内のキーと値のペアとして記述されます。構成ファイルでは、Spring 構成ユーティリティを使用して必要なエイリアスを記述することができます。
Java
XML
次の例は、Java でエイリアスを記述する方法を示しています。
@Bean
public XStreamMarshaller tradeMarshaller() {
Map<String, Class> aliases = new HashMap<>();
aliases.put("trade", Trade.class);
aliases.put("price", BigDecimal.class);
aliases.put("isin", String.class);
aliases.put("customer", String.class);
aliases.put("quantity", Long.class);
XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.setAliases(aliases);
return marshaller;
}
次の例は、エイリアスを XML で記述する方法を示しています。
<bean id="tradeMarshaller"
class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<util:map id="aliases">
<entry key="trade"
value="org.springframework.batch.samples.domain.trade.Trade" />
<entry key="price" value="java.math.BigDecimal" />
<entry key="isin" value="java.lang.String" />
<entry key="customer" value="java.lang.String" />
<entry key="quantity" value="java.lang.Long" />
</util:map>
</property>
</bean>
入力時に、リーダーは新しいフラグメントが開始されようとしていることを認識するまで XML リソースを読み取ります。デフォルトでは、リーダーは要素名を照合して、新しいフラグメントが開始されようとしていることを認識します。リーダーは、フラグメントからスタンドアロン XML ドキュメントを作成し、そのドキュメントをデシリアライザー(通常は Spring OXM Unmarshaller
のラッパー)に渡して、XML を Java オブジェクトにマッピングします。
要約すると、この手順は、Spring 構成によって提供されるインジェクションを使用する次の Java コードに類似しています。
StaxEventItemReader<Trade> xmlStaxEventItemReader = new StaxEventItemReader<>();
Resource resource = new ByteArrayResource(xmlResource.getBytes());
Map aliases = new HashMap();
aliases.put("trade","org.springframework.batch.samples.domain.trade.Trade");
aliases.put("price","java.math.BigDecimal");
aliases.put("customer","java.lang.String");
aliases.put("isin","java.lang.String");
aliases.put("quantity","java.lang.Long");
XStreamMarshaller unmarshaller = new XStreamMarshaller();
unmarshaller.setAliases(aliases);
xmlStaxEventItemReader.setUnmarshaller(unmarshaller);
xmlStaxEventItemReader.setResource(resource);
xmlStaxEventItemReader.setFragmentRootElementName("trade");
xmlStaxEventItemReader.open(new ExecutionContext());
boolean hasNext = true;
Trade trade = null;
while (hasNext) {
trade = xmlStaxEventItemReader.read();
if (trade == null) {
hasNext = false;
}
else {
System.out.println(trade);
}
}
StaxEventItemWriter
出力は入力に対して対称的に機能します。StaxEventItemWriter
には、Resource
、マーシャラー、rootTagName
が必要です。Java オブジェクトはマーシャラー(通常は標準の Spring OXM マーシャラー)に渡されます。マーシャラーは、OXM ツールによってフラグメントごとに生成された StartDocument
および EndDocument
イベントをフィルター処理するカスタムイベントライターを使用して Resource
に書き込みます。
Java
XML
次の Java の例では、MarshallingEventWriterSerializer
を使用しています。
@Bean
public StaxEventItemWriter itemWriter(Resource outputResource) {
return new StaxEventItemWriterBuilder<Trade>()
.name("tradesWriter")
.marshaller(tradeMarshaller())
.resource(outputResource)
.rootTagName("trade")
.overwriteOutput(true)
.build();
}
次の XML の例では、MarshallingEventWriterSerializer
を使用しています。
<bean id="itemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
<property name="resource" ref="outputResource" />
<property name="marshaller" ref="tradeMarshaller" />
<property name="rootTagName" value="trade" />
<property name="overwriteOutput" value="true" />
</bean>
上記の構成では、3 つの必須プロパティを設定し、既存のファイルを上書きできるかどうかを指定するためにこの章で前述したオプションの overwriteOutput=true
属性を設定します。
Java
XML
次の Java の例では、この章で前述した読み取りの例で使用したものと同じマーシャラーを使用しています。
@Bean
public XStreamMarshaller customerCreditMarshaller() {
XStreamMarshaller marshaller = new XStreamMarshaller();
Map<String, Class> aliases = new HashMap<>();
aliases.put("trade", Trade.class);
aliases.put("price", BigDecimal.class);
aliases.put("isin", String.class);
aliases.put("customer", String.class);
aliases.put("quantity", Long.class);
marshaller.setAliases(aliases);
return marshaller;
}
次の XML の例では、この章で前述した読み取りの例で使用したものと同じマーシャラーを使用しています。
<bean id="customerCreditMarshaller"
class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<util:map id="aliases">
<entry key="customer"
value="org.springframework.batch.samples.domain.trade.Trade" />
<entry key="price" value="java.math.BigDecimal" />
<entry key="isin" value="java.lang.String" />
<entry key="customer" value="java.lang.String" />
<entry key="quantity" value="java.lang.Long" />
</util:map>
</property>
</bean>
Java の例をまとめると、次のコードは、説明したすべてのポイントを示しており、必要なプロパティのプログラムによる設定を示しています。
FileSystemResource resource = new FileSystemResource("data/outputFile.xml")
Map aliases = new HashMap();
aliases.put("trade","org.springframework.batch.samples.domain.trade.Trade");
aliases.put("price","java.math.BigDecimal");
aliases.put("customer","java.lang.String");
aliases.put("isin","java.lang.String");
aliases.put("quantity","java.lang.Long");
Marshaller marshaller = new XStreamMarshaller();
marshaller.setAliases(aliases);
StaxEventItemWriter staxItemWriter =
new StaxEventItemWriterBuilder<Trade>()
.name("tradesWriter")
.marshaller(marshaller)
.resource(resource)
.rootTagName("trade")
.overwriteOutput(true)
.build();
staxItemWriter.afterPropertiesSet();
ExecutionContext executionContext = new ExecutionContext();
staxItemWriter.open(executionContext);
Trade trade = new Trade();
trade.setPrice(11.39);
trade.setIsin("XYZ0001");
trade.setQuantity(5L);
trade.setCustomer("Customer1");
staxItemWriter.write(trade);