OPEN - issue BATCH-116: Create XML input/output source which will work directly with StAX parser
http://opensource.atlassian.com/projects/spring/browse/BATCH-116 Added additional code coverage to infrastructure, validation to samples jobs, and integration tests for castor and xstream
This commit is contained in:
@@ -19,7 +19,7 @@
|
||||
|
||||
<!-- Temporary measure while we get to the bottom of the test failures on Bamboo -->
|
||||
<properties>
|
||||
<maven.test.skip>true</maven.test.skip>
|
||||
<maven.test.skip>true</maven.test.skip>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -92,6 +92,48 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xmlunit</groupId>
|
||||
<artifactId>xmlunit</artifactId>
|
||||
<version>1.1</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.ws</groupId>
|
||||
<artifactId>spring-oxm</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.castor</groupId>
|
||||
<artifactId>castor</artifactId>
|
||||
<version>1.1.2</version>
|
||||
<scope>test</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>stax</groupId>
|
||||
<artifactId>stax</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
<artifactId>xstream</artifactId>
|
||||
<version>1.2.1</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<!-- Reporting: it doesn't make much sense to have clover or Jdepend reports in this project but they are included by the parent anyway. -->
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root>
|
||||
<trade>
|
||||
<isin>isin1</isin>
|
||||
<quantity>1</quantity>
|
||||
<price>1</price>
|
||||
<customer>customer1</customer>
|
||||
</trade>
|
||||
|
||||
<trade>
|
||||
<isin>isin2</isin>
|
||||
<quantity>2</quantity>
|
||||
<price>2</price>
|
||||
<customer>customer2</customer>
|
||||
</trade>
|
||||
|
||||
<trade>
|
||||
<isin>isin3</isin>
|
||||
<quantity>3</quantity>
|
||||
<price>3</price>
|
||||
<customer>customer3</customer>
|
||||
</trade>
|
||||
|
||||
</root>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<records>
|
||||
<trade>
|
||||
<isin>XYZ0001</isin>
|
||||
<quantity>5</quantity>
|
||||
<price>11.39</price>
|
||||
<customer>Customer1</customer>
|
||||
</trade>
|
||||
<trade>
|
||||
<isin>XYZ0002</isin>
|
||||
<quantity>2</quantity>
|
||||
<price>72.99</price>
|
||||
<customer>Customer2</customer>
|
||||
</trade>
|
||||
<trade>
|
||||
<isin>XYZ0003</isin>
|
||||
<quantity>9</quantity>
|
||||
<price>99.99</price>
|
||||
<customer>Customer3</customer>
|
||||
</trade>
|
||||
</records>
|
||||
@@ -0,0 +1,23 @@
|
||||
<mapping>
|
||||
<class name="org.springframework.batch.io.oxm.domain.Trade">
|
||||
|
||||
<map-to xml="trade" />
|
||||
|
||||
<field name="isin">
|
||||
<bind-xml name="isin" node="element" />
|
||||
</field>
|
||||
|
||||
<field name="quantity">
|
||||
<bind-xml name="quantity" node="element" />
|
||||
</field>
|
||||
|
||||
<field name="price">
|
||||
<bind-xml name="price" node="element" />
|
||||
</field>
|
||||
|
||||
<field name="customer">
|
||||
<bind-xml name="customer" node="element" />
|
||||
</field>
|
||||
|
||||
</class>
|
||||
</mapping>
|
||||
Reference in New Issue
Block a user