BATCH-484: added documentation for ItemTransformerItemWriter, ItemTransformer, and CompsiteItemTransformer.

This commit is contained in:
lucasward
2008-03-19 23:39:11 +00:00
parent fc1e7debd9
commit 7f64b5c39e

View File

@@ -1729,6 +1729,193 @@ itemReader.close(executionContext);</programlisting>
</programlisting>
</section>
<section>
<title>Item Transforming</title>
<para>The <classname>ItemReader</classname> and
<classname>ItemWriter</classname> interfaces have been discussed in detail
in this chapter, but what if you want to insert business logic before
writing? One option for both reading and writing is to use the composite
pattern. That is, create an <classname>ItemWriter</classname> that
contains another <classname>ItemWriter</classname>, or an
<classname>ItemReader</classname> that contains another
<classname>ItemReader</classname>. For example:</para>
<programlisting> public class CompositeItemWriter implements ItemWriter {
ItemWriter itemWriter;
public CompositeItemWriter(ItemWriter itemWriter) {
this.itemWriter = itemWriter;
}
public void write(Object item) throws Exception {
//Add business logic here
itemWriter.write(item);
}
public void clear() throws ClearFailedException {
itemWriter.clear();
}
public void flush() throws FlushFailedException {
itemWriter.flush();
}
}</programlisting>
<para>The class above contains another <classname>ItemWriter</classname>
that it delgates to after having provided some business logic. It should
be noted that the <methodname>clear</methodname> and
<methodname>flush</methodname> methods must be propogated as well so that
the delegate <classname>ItemWriter</classname> is notified. This pattern
could easily be used for an <classname>ItemReader</classname> as well,
perhaps to obtain more reference data based upon the input that was
provided by the main <classname>ItemReader</classname>. This pattern is
very useful if you need to control the call to
<classname>write</classname> yourself. However, if you only want to
'transform' the item passed in for writing before it is actual written,
there isn't much need to call <methodname>write</methodname> yourself, you
just want to modify the item. For this scenario, Spring Batch provides the
<classname>ItemTransformer</classname> interface:</para>
<programlisting> public interface ItemTransformer {
Object transform(Object item) throws Exception;
}</programlisting>
<para>An ItemTransformer interface is very simple, given one object,
transorm it and return another. The object provided may or may not be of
the same type. The point is that business logic may be applied within
transform, and is completely up to the developer to create. An
<classname>ItemTransformer</classname> is used as part of the
<classname>ItemTransformerItemWriter</classname>, which accepts an
<classname>ItemWriter</classname> and an
<classname>ItemTransformer</classname>, passing the item first to the
transformer, before writing it. For example, assuming an
<classname>ItemReader</classname> provides a class of type Foo, and it
needs to be converted to type Bar before being written out. An
<classname>ItemTransformer</classname> can be written that perform the
conversion:</para>
<programlisting> public class Foo {}
public class Bar {
public Bar(Foo foo) {}
}
public class FooTransformer implements ItemTransformer{
//Preform simple transformation, convert a Foo to a Barr
public Object transform(Object item) throws Exception {
assertTrue(item instanceof Foo);
Foo foo = (Foo)item;
return new Bar(foo);
}
}
public class BarWriter implements ItemWriter{
public void write(Object item) throws Exception {
assertTrue(item instanceof Bar);
}
//rest of class ommitted for clarity
}</programlisting>
<para>In the very simple example above, there is a class
<classname>Foo</classname>, a class <classname>Bar</classname>, and a
class <classname>FooTransformer</classname> that adheres to the
<classname>ItemTransformer</classname> interface. The transformation is
simple, but any type of transformation could be done here. The
<classname>BarWriter</classname> will be used to write out 'Bars',
throwing an exception if any other type is provided. Similarly, the
FooTransformer will throw an exception if anything but a
<classname>Foo</classname> is provided. An
<classname>ItemTransformerItemWriter</classname> can then be used like a
normal ItemWriter. It will be passed a <classname>Foo</classname> for
writing, which will be passed to the transformer, and a
<classname>Bar</classname> returned. The resulting
<classname>Bar</classname> will then be written:</para>
<programlisting> ItemTransformerItemWriter itemTransformerItemWriter = new ItemTransformerItemWriter();
itemTransformerItemWriter.setItemTransformer(new FooTransformer());
itemTransformerItemWriter.setDelegate(new BarWriter());
itemTransformerItemWriter.write(new Foo());</programlisting>
<section>
<title>Chaining ItemTransformers</title>
<para>Performing a single transformation is useful in many scenarios,
but what if you want to 'chain' together multiple ItemTransformers? This
can be accomplished using a
<classname>CompositeItemTransformer</classname>. To update the previous,
single transformation, example, <classname>Foo</classname> will be
Transformed to <classname>Bar</classname>, which will be transformed to
<classname>Foobar</classname> and written out:</para>
<programlisting> public class Foo {}
public class Bar {
public Bar(Foo foo) {}
}
public class Foobar{
public Foobar(Bar bar){}
}
public class FooTransformer implements ItemTransformer{
//Preform simple transformation, convert a Foo to a Barr
public Object transform(Object item) throws Exception {
assertTrue(item instanceof Foo);
Foo foo = (Foo)item;
return new Bar(foo);
}
}
public class BarTransformer implements ItemTransformer{
public Object transform(Object item) throws Exception {
assertTrue(item instanceof Bar);
return new Foobar((Bar)item);
}
}
public class FoobarWriter implements ItemWriter{
public void write(Object item) throws Exception {
assertTrue(item instanceof Foobar);
}
//rest of class ommitted for clarity
}</programlisting>
<para>A <classname>FooTransformer</classname> and
<classname>BarTransformer</classname> can be 'chained' together to give
the resultant <classname>Foobar</classname>:</para>
<programlisting> CompositeItemTransformer compositeTransformer = new CompositeItemTransformer();
List itemTransformers = new ArrayList();
itemTransformers.add(new FooTransformer());
itemTransformers.add(new BarTransformer());
compositeTransformer.setItemTransformers(itemTransformers);</programlisting>
<para>The compositeTransformer could be said to accept a
<classname>Foo</classname> and return a <classname>Foobar</classname>.
Clients of the composite transformer don't need to know that there are
actually two separate transformations taking place. By updating the
example from above to use the composite transformer, the correct class
can be passed to <classname>FoobarWriter</classname>:</para>
<programlisting> ItemTransformerItemWriter itemTransformerItemWriter = new ItemTransformerItemWriter();
<emphasis role="bold">itemTransformerItemWriter.setItemTransformer(compositeTransformer);</emphasis>
itemTransformerItemWriter.setDelegate(new FoobarWriter());
itemTransformerItemWriter.write(new Foo());</programlisting>
</section>
</section>
<section>
<title id="infrastructure.5">Validating Input</title>