diff --git a/integration/pom.xml b/integration/pom.xml
index 9b341c5a1..f7bb58fb4 100644
--- a/integration/pom.xml
+++ b/integration/pom.xml
@@ -19,7 +19,7 @@
- true
+ true
@@ -92,6 +92,48 @@
+
+ xmlunit
+ xmlunit
+ 1.1
+ test
+ true
+
+
+ org.springframework.ws
+ spring-oxm
+ 1.0.0
+ test
+ true
+
+
+ org.springframework
+ spring-beans
+
+
+ org.springframework
+ spring-core
+
+
+
+
+ org.codehaus.castor
+ castor
+ 1.1.2
+ test
+ true
+
+
+ stax
+ stax
+ true
+
+
+ com.thoughtworks.xstream
+ xstream
+ 1.2.1
+ true
+
diff --git a/integration/src/test/java/org/springframework/batch/io/oxm/AbstractStaxEventReaderInputSourceTests.java b/integration/src/test/java/org/springframework/batch/io/oxm/AbstractStaxEventReaderInputSourceTests.java
new file mode 100644
index 000000000..9b3879227
--- /dev/null
+++ b/integration/src/test/java/org/springframework/batch/io/oxm/AbstractStaxEventReaderInputSourceTests.java
@@ -0,0 +1,79 @@
+package org.springframework.batch.io.oxm;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.springframework.batch.io.oxm.domain.Trade;
+import org.springframework.batch.io.stax.StaxEventReaderInputSource;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.oxm.Unmarshaller;
+
+public abstract class AbstractStaxEventReaderInputSourceTests extends TestCase {
+
+ private StaxEventReaderInputSource source = new StaxEventReaderInputSource();
+
+ protected Resource resource = new ClassPathResource(
+ "org/springframework/batch/io/oxm/input.xml");
+
+
+ protected void setUp() throws Exception {
+ //TODO sensible resource allocation
+ source.setResource(resource);
+
+ source.setFragmentRootElementName("trade");
+ UnmarshallingFragmentDeserializer deserializer = new UnmarshallingFragmentDeserializer(getUnmarshaller());
+ source.setFragmentDeserializer(deserializer);
+ }
+
+ public void testRead() {
+ Object result;
+ List results = new ArrayList();
+ while ((result = source.read()) != null) {
+ results.add(result);
+ }
+ checkResults(results);
+
+ }
+
+ /**
+ * @return Unmarshaller specific to the OXM library used
+ */
+ protected abstract Unmarshaller getUnmarshaller() throws Exception;
+
+ /**
+ * @param results list of domain objects returned by input source
+ */
+ protected void checkResults(List results){
+ assertEquals(3, results.size());
+
+ Trade trade1 = (Trade) results.get(0);
+ assertEquals("XYZ0001", trade1.getIsin());
+ assertEquals(5, trade1.getQuantity());
+ assertEquals(BigDecimal.valueOf(11.39), trade1.getPrice());
+ assertEquals("Customer1", trade1.getCustomer());
+
+ Trade trade2 = (Trade) results.get(1);
+ assertEquals("XYZ0002", trade2.getIsin());
+ assertEquals(2, trade2.getQuantity());
+ assertEquals(BigDecimal.valueOf(72.99), trade2.getPrice());
+ assertEquals("Customer2", trade2.getCustomer());
+
+ Trade trade3 = (Trade) results.get(2);
+ assertEquals("XYZ0003", trade3.getIsin());
+ assertEquals(9, trade3.getQuantity());
+ assertEquals(BigDecimal.valueOf(99.99), trade3.getPrice());
+ assertEquals("Customer3", trade3.getCustomer());
+ }
+
+ protected void tearDown() throws Exception {
+ source.close();
+ }
+
+ public void setResource(Resource resource) {
+ this.resource = resource;
+ }
+}
diff --git a/integration/src/test/java/org/springframework/batch/io/oxm/AbstractStaxEventWriterOutputSourceTests.java b/integration/src/test/java/org/springframework/batch/io/oxm/AbstractStaxEventWriterOutputSourceTests.java
new file mode 100644
index 000000000..fbd282ba2
--- /dev/null
+++ b/integration/src/test/java/org/springframework/batch/io/oxm/AbstractStaxEventWriterOutputSourceTests.java
@@ -0,0 +1,73 @@
+package org.springframework.batch.io.oxm;
+
+import java.io.File;
+import java.io.FileReader;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.custommonkey.xmlunit.XMLAssert;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.springframework.batch.io.oxm.domain.Trade;
+import org.springframework.batch.io.stax.StaxEventWriterOutputSource;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+import org.springframework.oxm.Marshaller;
+
+public abstract class AbstractStaxEventWriterOutputSourceTests extends TestCase {
+
+ private StaxEventWriterOutputSource source = new StaxEventWriterOutputSource();
+
+ private Resource resource;
+
+ File outputFile;
+
+ protected Resource expected = new ClassPathResource("expected-output.xml", getClass());
+
+
+ protected List objects = new ArrayList() {{
+ add(new Trade("isin1", 1, new BigDecimal(1.0), "customer1"));
+ add(new Trade("isin2", 2, new BigDecimal(2.0), "customer2"));
+ add(new Trade("isin3", 3, new BigDecimal(3.0), "customer3"));
+ }};
+
+ /**
+ * Write list of domain objects and check the output file.
+ */
+ public void testWrite() throws Exception {
+ for (Iterator iterator = objects.listIterator(); iterator.hasNext();) {
+ source.write(iterator.next());
+ }
+ source.close();
+ XMLUnit.setIgnoreWhitespace(true);
+ XMLAssert.assertXMLEqual(new FileReader(expected.getFile()), new FileReader(resource.getFile()));
+
+ }
+
+
+ protected void setUp() throws Exception {
+ //File outputFile = File.createTempFile("AbstractStaxStreamWriterOutputSourceTests", "xml");
+ outputFile = File.createTempFile(this.getClass().getSimpleName(), ".xml");
+ resource = new FileSystemResource(outputFile);
+ source.setResource(resource);
+
+ MarshallingObjectToXmlSerializer mapper = new MarshallingObjectToXmlSerializer(getMarshaller());
+ source.setSerializer(mapper);
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ outputFile.delete();
+ }
+
+ /**
+ * @return Marshaller specific for the OXM technology being used.
+ */
+ protected abstract Marshaller getMarshaller() throws Exception;
+
+}
diff --git a/integration/src/test/java/org/springframework/batch/io/oxm/CastorMarshallingTests.java b/integration/src/test/java/org/springframework/batch/io/oxm/CastorMarshallingTests.java
new file mode 100644
index 000000000..3877246b3
--- /dev/null
+++ b/integration/src/test/java/org/springframework/batch/io/oxm/CastorMarshallingTests.java
@@ -0,0 +1,20 @@
+package org.springframework.batch.io.oxm;
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.oxm.Marshaller;
+import org.springframework.oxm.castor.CastorMarshaller;
+
+public class CastorMarshallingTests extends AbstractStaxEventWriterOutputSourceTests {
+
+ protected Marshaller getMarshaller() throws Exception {
+
+ CastorMarshaller marshaller = new CastorMarshaller();
+ // marshaller.setTargetClass(Trade.class);
+ marshaller.setMappingLocation(new ClassPathResource("mapping-castor.xml", getClass()));
+ // there is no way to call
+ // org.exolab.castor.xml.Marshaller.setSupressXMLDeclaration();
+ marshaller.afterPropertiesSet();
+ return marshaller;
+ }
+
+}
diff --git a/integration/src/test/java/org/springframework/batch/io/oxm/CastorUnmarshallingTests.java b/integration/src/test/java/org/springframework/batch/io/oxm/CastorUnmarshallingTests.java
new file mode 100644
index 000000000..25ba7efee
--- /dev/null
+++ b/integration/src/test/java/org/springframework/batch/io/oxm/CastorUnmarshallingTests.java
@@ -0,0 +1,18 @@
+package org.springframework.batch.io.oxm;
+
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.oxm.Unmarshaller;
+import org.springframework.oxm.castor.CastorMarshaller;
+
+public class CastorUnmarshallingTests extends AbstractStaxEventReaderInputSourceTests {
+
+ protected Unmarshaller getUnmarshaller() throws Exception {
+ CastorMarshaller unmarshaller = new CastorMarshaller();
+ unmarshaller.setMappingLocation(new ClassPathResource("mapping-castor.xml", getClass()));
+ // alternatively target class can be set
+ //unmarshaller.setTargetClass(Trade.class);
+ unmarshaller.afterPropertiesSet();
+ return unmarshaller;
+ }
+
+}
diff --git a/integration/src/test/java/org/springframework/batch/io/oxm/XStreamMarshallingTests.java b/integration/src/test/java/org/springframework/batch/io/oxm/XStreamMarshallingTests.java
new file mode 100644
index 000000000..6e8827b4a
--- /dev/null
+++ b/integration/src/test/java/org/springframework/batch/io/oxm/XStreamMarshallingTests.java
@@ -0,0 +1,18 @@
+package org.springframework.batch.io.oxm;
+
+import org.springframework.batch.io.oxm.domain.Trade;
+import org.springframework.oxm.Marshaller;
+import org.springframework.oxm.xstream.XStreamMarshaller;
+
+public class XStreamMarshallingTests extends
+ AbstractStaxEventWriterOutputSourceTests {
+
+ protected Marshaller getMarshaller() throws Exception {
+ XStreamMarshaller marshaller = new XStreamMarshaller();
+ marshaller.addAlias("trade", Trade.class);
+ //in XStreamMarshaller.marshalSaxHandlers() method is used SaxWriter, which is configured
+ //to include enclosing document (SaxWriter.includeEnclosingDocument is always set to TRUE)
+ return marshaller;
+ }
+
+}
diff --git a/integration/src/test/java/org/springframework/batch/io/oxm/XStreamUnmarshallingTests.java b/integration/src/test/java/org/springframework/batch/io/oxm/XStreamUnmarshallingTests.java
new file mode 100644
index 000000000..89eeba3c1
--- /dev/null
+++ b/integration/src/test/java/org/springframework/batch/io/oxm/XStreamUnmarshallingTests.java
@@ -0,0 +1,20 @@
+package org.springframework.batch.io.oxm;
+
+import java.math.BigDecimal;
+
+import org.springframework.batch.io.oxm.domain.Trade;
+import org.springframework.oxm.Unmarshaller;
+import org.springframework.oxm.xstream.XStreamMarshaller;
+
+public class XStreamUnmarshallingTests extends AbstractStaxEventReaderInputSourceTests {
+
+ protected Unmarshaller getUnmarshaller() throws Exception {
+ XStreamMarshaller unmarshaller = new XStreamMarshaller();
+ unmarshaller.addAlias("trade", Trade.class);
+ unmarshaller.addAlias("isin", String.class);
+ unmarshaller.addAlias("customer", String.class);
+ unmarshaller.addAlias("price", BigDecimal.class);
+ return unmarshaller;
+ }
+
+}
diff --git a/integration/src/test/java/org/springframework/batch/io/oxm/domain/Trade.java b/integration/src/test/java/org/springframework/batch/io/oxm/domain/Trade.java
new file mode 100644
index 000000000..bc959b60f
--- /dev/null
+++ b/integration/src/test/java/org/springframework/batch/io/oxm/domain/Trade.java
@@ -0,0 +1,72 @@
+package org.springframework.batch.io.oxm.domain;
+
+import java.math.BigDecimal;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+
+
+/**
+ * @author Rob Harrop
+ */
+public class Trade {
+ private String isin = "";
+ private long quantity = 0;
+ private BigDecimal price = new BigDecimal(0);
+ private String customer = "";
+
+ public Trade() {
+ }
+
+ public Trade(String isin, long quantity, BigDecimal price, String customer){
+ this.isin = isin;
+ this.quantity = quantity;
+ this.price = price;
+ this.customer = customer;
+ }
+
+ public void setCustomer(String customer) {
+ this.customer = customer;
+ }
+
+ public void setIsin(String isin) {
+ this.isin = isin;
+ }
+
+ public void setPrice(BigDecimal price) {
+ this.price = price;
+ }
+
+ public void setQuantity(long quantity) {
+ this.quantity = quantity;
+ }
+
+ public String getIsin() {
+ return isin;
+ }
+
+ public BigDecimal getPrice() {
+ return price;
+ }
+
+ public long getQuantity() {
+ return quantity;
+ }
+
+ public String getCustomer() {
+ return customer;
+ }
+
+ public String toString() {
+ return "Trade: [isin=" + this.isin + ",quantity=" + this.quantity + ",price="
+ + this.price + ",customer=" + this.customer + "]";
+ }
+
+ public boolean equals(Object o) {
+ return EqualsBuilder.reflectionEquals(this, o);
+ }
+
+ public int hashCode() {
+ return HashCodeBuilder.reflectionHashCode(this);
+ }
+}
diff --git a/integration/src/test/resources/org/springframework/batch/io/oxm/expected-output.xml b/integration/src/test/resources/org/springframework/batch/io/oxm/expected-output.xml
new file mode 100644
index 000000000..d0644b0c4
--- /dev/null
+++ b/integration/src/test/resources/org/springframework/batch/io/oxm/expected-output.xml
@@ -0,0 +1,24 @@
+
+
+
+ isin1
+ 1
+ 1
+ customer1
+
+
+
+ isin2
+ 2
+ 2
+ customer2
+
+
+
+ isin3
+ 3
+ 3
+ customer3
+
+
+
\ No newline at end of file
diff --git a/integration/src/test/resources/org/springframework/batch/io/oxm/input.xml b/integration/src/test/resources/org/springframework/batch/io/oxm/input.xml
new file mode 100644
index 000000000..0e76751a4
--- /dev/null
+++ b/integration/src/test/resources/org/springframework/batch/io/oxm/input.xml
@@ -0,0 +1,21 @@
+
+
+
+ XYZ0001
+ 5
+ 11.39
+ Customer1
+
+
+ XYZ0002
+ 2
+ 72.99
+ Customer2
+
+
+ XYZ0003
+ 9
+ 99.99
+ Customer3
+
+
diff --git a/integration/src/test/resources/org/springframework/batch/io/oxm/mapping-castor.xml b/integration/src/test/resources/org/springframework/batch/io/oxm/mapping-castor.xml
new file mode 100644
index 000000000..b9306dbee
--- /dev/null
+++ b/integration/src/test/resources/org/springframework/batch/io/oxm/mapping-castor.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file