diff --git a/docs/src/site/docbook/reference/readersAndWriters.xml b/docs/src/site/docbook/reference/readersAndWriters.xml index 77ed703bf..172d13aa3 100644 --- a/docs/src/site/docbook/reference/readersAndWriters.xml +++ b/docs/src/site/docbook/reference/readersAndWriters.xml @@ -151,61 +151,6 @@ persisted in the database before commit. -
- List Item Readers and Common Custom Item - Reader Behavior - - The ListItemReader, as mentioned - above, is useful for testing and probably not too useful as something used - in typical batch processing. One instructive use is to see how narrow the - responsiblity of ItemReaders are. They simply provide a method that allows - us to continue reading items until the items are exhausted much like an - iterator. In addition,, it is expected that projects will create custom - Item Readers. As a means of illustrating the standard properties and - behaviors of other framework-provided ItemReaders like mapping - unstructured items into objects through the use of tokenizing we will - extend the ListItemReader to supporting mapping. The ItemReader interface - defines a single method called read(). - The read() method returns the next object - to be provided, much like an iterator. The definition of this method will - contain the logic that decides what object to return, performs any object - construction or other work that needs to occur, and finally returns the - object. We inherit this behavior from ListItemReader. We will add two - methods, setFieldSetMapper(), to enable - the mapping behavior and setTokenizer(), - to enabling parsing of List Items. It this example the items in the list - are a simple array of delimited strings.. - - Here is our custom list item Reader that supplies mapping or binding - behavior as follows: - protected static class ListPlayerReader extends ListItemReader { - private FieldSetMapper fieldSetMapper; - private LineTokenizer tokenizer = null; - - public ListPlayerReader(List list) { - super(list); - } - - public void setFieldSetMapper(FieldSetMapper fieldSetMapper) { - this.fieldSetMapper = fieldSetMapper; - } - - public void setTokenizer(LineTokenizer tokenizer) { - this.tokenizer = tokenizer; - } - - - } - - - We will tag it as an Player Reader for reasons you'll see next as we - map Player objects from input strings. In this example we have inherited - the read() behavior that allows us to read from a List in memory and - provided a way to map arbitrary streams into objects and added the ability - to map FieldSets to objects. We will see how to take advantage of this - next. -
-
Flat Files @@ -517,8 +462,8 @@ boolean booleanValue = fs.readBoolean(2); FlatFileItemReader itemReader = new FlatFileItemReader(); itemReader.setResource = new FileSystemResource("resources/players.csv"); //DelimitedLineTokenizer defaults to comma as it's delimiter -itemReader.setLineTokenizer = new DelimitedLineTokenizer(); -itemReader.setFieldSetMapper = new PlayerFieldSetMapper(); +itemReader.setLineTokenizer(new DelimitedLineTokenizer()); +itemReader.setFieldSetMapper(new PlayerFieldSetMapper()); itemReader.read(); @@ -567,7 +512,7 @@ itemReader.read();
- BeanWrapperFieldSetMapper + Automapping FieldSets to Domain Objects For many, having to write a specific FieldSetMapper is equally as cumbersome as writing a specific RowMapper for a JdbcTemplate. @@ -595,7 +540,7 @@ itemReader.read();
- FixedLengthLineTokenizer + Fixed Length file formats So far only delimited files have been discussed in much detail, however, they respresent only half of the file reading picture. Many @@ -648,7 +593,7 @@ UK21341EAH4521535.11customer5
- PrefixMatchingCompositeLineTokenizer + Multiple record types within a single file All of the file reading examples up to this point have all made a key assumption for simplicity's sake: one record equals one line. @@ -820,38 +765,13 @@ FOT;2;2;267.34 Constraints on streaming XML - StAX API is used for I/O as other standard XML APIs do not fit - batch processing requirements (DOM loads the whole input into memory at - once and SAX controls the parsing process allowing the user only to - provide callbacks). + The StAX API is used for I/O as other standard XML parsing APIs do + not fit batch processing requirements (DOM loads the whole input into + memory at once and SAX controls the parsing process allowing the user + only to provide callbacks). - Spring Batch is not tied to any particular OXM technology. Typical - use is to delegate OXM - to Spring WS, which provides uniform abstraction for - the most popular OXM technologies. However dependency on Spring WS is - optional and you can choose to implement Spring Batch specific interfaces - if desired. The relationship to the technologies that OXM supports can be - shown as the following: - - - - - - - - - - - Figure X: OXM Binding - - - Lets take a closer look how XML input and output work in batch. It + Lets take a closer look how XML input and output works in batch. It is assumed the XML resource is a collection of 'fragments' corresponding to individual records. Note that OXM tools are designed to work with standalone XML documents rather than XML fragments cut out of an XML @@ -874,11 +794,37 @@ FOT;2;2;267.34 Figure X: XML Inputs - - The StaxEventItemReader configuration provides a typical setup for the processing of records from an XML input stream. First, lets examine a set of xml records that the StaxEventItemReader can process. - - - + Spring Batch uses Object/XML Mapping (OXM) to bind fragments to + objects. However, Spring Batch is not tied to any particular OXM + technology. Typical use is to delegate OXM + to Spring WS, which provides uniform abstraction for + the most popular OXM technologies. The dependency on Spring WS is optional + and you can choose to implement Spring Batch specific interfaces if + desired. The relationship to the technologies that OXM supports can be + shown as the following: + + + + + + + + + + + Figure X: OXM Binding + + + The StaxEventItemReader configuration provides a typical setup for + the processing of records from an XML input stream. First, lets examine a + set of xml records that the StaxEventItemReader can process. + + <?xml version="1.0" encoding="UTF-8"?> <records> <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> @@ -899,63 +845,31 @@ FOT;2;2;267.34 <price>99.99</price> <customer>Customer3</customer> </trade> - <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> - <isin>XYZ0001</isin> - <quantity>5</quantity> - <price>11.39</price> - <customer>Customer1</customer> - </trade> - <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> - <isin>XYZ0002</isin> - <quantity>2</quantity> - <price>72.99</price> - <customer>Customer2c</customer> - </trade> - <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> - <isin>XYZ0003</isin> - <quantity>9</quantity> - <price>99.99</price> - <customer>Customer3</customer> - </trade> - <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> - <isin>XYZ0001</isin> - <quantity>5</quantity> - <price>11.39</price> - <customer>Customer1</customer> - </trade> - <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> - <isin>XYZ0002</isin> - <quantity>2</quantity> - <price>72.99</price> - <customer>Customer2c</customer> - </trade> - <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> - <isin>XYZ0003</isin> - <quantity>9</quantity> - <price>99.99</price> - <customer>Customer3</customer> - </trade> </records> - - + - - To be able to process the XML records we need the following: + To be able to process the XML records we need the following: - - Root Element Name - this is name of the root element of the fragment that constitutes the object to be mapped in. The example configuration - demonstrates this with the value of trade. - - - Resource - This is a Spring Resource that in the case of this example will abstract the details of opening a file for reading content. - - - Fragment Deserializer - this is the UnMarshalling facility provided by Spring OXM for mapping the XML fragment to an object. - - - - - <property name="itemReader"> + + Root Element Name - this is name of the root element of the + fragment that constitutes the object to be mapped. The example + configuration demonstrates this with the value of trade. + + + + Resource - This is a Spring Resource that in the case of this + example will abstract the details of opening a file for reading + content. + + + + Fragment Deserializer - this is the UnMarshalling facility + provided by Spring OXM for mapping the XML fragment to an + object. + + + + <property name="itemReader"> <bean class="org.springframework.batch.io.xml.StaxEventItemReader"> <property name="fragmentRootElementName" value="trade" /> <property name="resource" value="data/staxJob/input/20070918.testStream.xmlFileStep.xml" /> @@ -970,18 +884,17 @@ FOT;2;2;267.34 </property> </bean> </property> - - + - Notice that it requires an alias passed in as a map with the - first key and value being the name of the fragment and the object - type that it will be mapped. Then, similar to a FieldSet, the - names of the other elements that map to fields within the object - type are described as key/value pairs in the map. In the - configuration file we can use a spring configuration utility to - described the required alias as follows: - - + Notice that in this example we have chosen to use an + XStreamMarshaller that requires an alias passed in as a map with the first + key and value being the name of the fragment (i.e. root element) and the + object type to bind. Then, similar to a FieldSet, the names of the other + elements that map to fields within the object type are described as + key/value pairs in the map. In the configuration file we can use a spring + configuration utility to describe the required alias as follows: + + <util:map id="aliases"> <entry key="trade" value="org.springframework.batch.sample.domain.Trade" /> @@ -990,49 +903,49 @@ FOT;2;2;267.34 <entry key="price" value="java.math.BigDecimal" /> <entry key="customer" value="java.lang.String" /> </util:map> - - + On input the reader reads the XML resource until it recognizes a new fragment is about to start (by matching the tag name by default). The reader creates a standalone XML document from the fragment (or at least makes it appear so) and passes the document to a deserializer (typically a - wrapper around Spring WS Unmarshaller) to map the XML to a Java + wrapper around a Spring WS Unmarshaller) to map the XML to a Java object. - - In summary, if you were to see this in scripted code like Java the injection provided by the spring configuration would look something like the following: - - - - def xmlStaxEventItemReader = new StaxEventItemReader() - resource = new ByteArrayResource(xmlResource.getBytes()) + In summary, if you were to see this in scripted code like Java the + injection provided by the spring configuration would look something like + the following: - def aliases = ["trade":"org.springframework.batch.sample.domain.Trade", - "isin":"java.lang.String", - "quantity":"long", - "price":"java.math.BigDecimal", - "customer":"java.lang.String"] - def marshaller = new XStreamMarshaller() - marshaller.setAliases(aliases) - xmlStaxEventItemReader.setFragmentDeserializer(new UnmarshallingEventReaderDeserializer(marshaller)) - xmlStaxEventItemReader.setResource(resource) - xmlStaxEventItemReader.setFragmentRootElementName("trade") - def executionContext = new ExecutionContext() - xmlStaxEventItemReader.open(executionContext); + + StaxEventItemReader xmlStaxEventItemReader = new StaxEventItemReader() + Resource resource = new ByteArrayResource(xmlResource.getBytes()) - def hasNext = true + Map aliases = new HashMap(); + aliases.put("trade","org.springframework.batch.sample.domain.Trade"); + aliases.put("isin","java.lang.String"); + aliases.put("quantity","long"); + aliases.put("price","java.math.BigDecimal"); + aliases.put("customer","java.lang.String"); + Marshaller marshaller = new XStreamMarshaller(); + marshaller.setAliases(aliases); + xmlStaxEventItemReader.setFragmentDeserializer(new UnmarshallingEventReaderDeserializer(marshaller)); + xmlStaxEventItemReader.setResource(resource); + xmlStaxEventItemReader.setFragmentRootElementName("trade"); + xmlStaxEventItemReader.open(new ExecutionContext()); + + boolean hasNext = true + while (hasNext) { - trade = xmlStaxEventItemReader.read() + trade = xmlStaxEventItemReader.read(); if (trade == null) { - hasNext = false + hasNext = false; } else { - println trade + println trade; } } - - + + Output works symetrically to input. Java object is passed to a serializer (typically a wrapper around Spring WS Marshaller) which writes to output using a custom event writer that filters the StartDocument and @@ -1041,6 +954,18 @@ FOT;2;2;267.34 For example configuration of XML input and output see the sample xmlStaxJob. //TODO inline the example once it is not subject to change + show sample input file + +
+ StaxEventItemReader + + +
+ +
+ StaxEventItemWriter + + +
@@ -1079,4 +1004,59 @@ FOT;2;2;267.34
- + +
+ Creating Custom ItemReaders and ItemWriters + + + The ListItemReader, as mentioned + above, is useful for testing and probably not too useful as something used + in typical batch processing. One instructive use is to see how narrow the + responsiblity of ItemReaders are. They simply provide a method that allows + us to continue reading items until the items are exhausted much like an + iterator. In addition,, it is expected that projects will create custom + Item Readers. As a means of illustrating the standard properties and + behaviors of other framework-provided ItemReaders like mapping + unstructured items into objects through the use of tokenizing we will + extend the ListItemReader to supporting mapping. The ItemReader interface + defines a single method called read(). + The read() method returns the next object + to be provided, much like an iterator. The definition of this method will + contain the logic that decides what object to return, performs any object + construction or other work that needs to occur, and finally returns the + object. We inherit this behavior from ListItemReader. We will add two + methods, setFieldSetMapper(), to enable + the mapping behavior and setTokenizer(), + to enabling parsing of List Items. It this example the items in the list + are a simple array of delimited strings.. + + Here is our custom list item Reader that supplies mapping or binding + behavior as follows: + protected static class ListPlayerReader extends ListItemReader { + private FieldSetMapper fieldSetMapper; + private LineTokenizer tokenizer = null; + + public ListPlayerReader(List list) { + super(list); + } + + public void setFieldSetMapper(FieldSetMapper fieldSetMapper) { + this.fieldSetMapper = fieldSetMapper; + } + + public void setTokenizer(LineTokenizer tokenizer) { + this.tokenizer = tokenizer; + } + + + } + + + We will tag it as an Player Reader for reasons you'll see next as we + map Player objects from input strings. In this example we have inherited + the read() behavior that allows us to read from a List in memory and + provided a way to map arbitrary streams into objects and added the ability + to map FieldSets to objects. We will see how to take advantage of this + next. +
+ \ No newline at end of file