RESOLVED - issue BATCH-1430: StaxEventItemWriter: Declare additional namespaces at the top-level element

This commit is contained in:
dsyer
2010-01-05 14:26:18 +00:00
parent d0f94cb0ee
commit 0d8cb85c10
17 changed files with 2400 additions and 36 deletions

View File

@@ -1,11 +1,14 @@
package org.springframework.batch.io.oxm;
import static org.junit.Assert.assertEquals;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import junit.framework.TestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.io.oxm.domain.Trade;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.xml.StaxEventItemReader;
@@ -13,28 +16,32 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.oxm.Unmarshaller;
public abstract class AbstractStaxEventReaderItemReaderTests extends TestCase {
public abstract class AbstractStaxEventReaderItemReaderTests {
private StaxEventItemReader<Trade> source = new StaxEventItemReader<Trade>();
protected StaxEventItemReader<Trade> reader = new StaxEventItemReader<Trade>();
protected Resource resource = new ClassPathResource("org/springframework/batch/io/oxm/input.xml");
protected void setUp() throws Exception {
@Before
public void setUp() throws Exception {
source.setResource(resource);
reader.setResource(resource);
source.setFragmentRootElementName("trade");
reader.setFragmentRootElementName("trade");
source.setUnmarshaller(getUnmarshaller());
reader.setUnmarshaller(getUnmarshaller());
source.open(new ExecutionContext());
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
}
@Test
public void testRead() throws Exception {
Trade result;
List<Trade> results = new ArrayList<Trade>();
while ((result = source.read()) != null) {
while ((result = reader.read()) != null) {
results.add(result);
}
checkResults(results);
@@ -71,8 +78,9 @@ public abstract class AbstractStaxEventReaderItemReaderTests extends TestCase {
assertEquals("Customer3", trade3.getCustomer());
}
protected void tearDown() throws Exception {
source.close();
@After
public void tearDown() throws Exception {
reader.close();
}
public void setResource(Resource resource) {

View File

@@ -33,11 +33,11 @@ public abstract class AbstractStaxEventWriterItemWriterTests {
private static final int MAX_WRITE = 100;
private StaxEventItemWriter<Trade> writer = new StaxEventItemWriter<Trade>();
protected StaxEventItemWriter<Trade> writer = new StaxEventItemWriter<Trade>();
private Resource resource;
File outputFile;
private File outputFile;
protected Resource expected = new ClassPathResource("expected-output.xml", getClass());
@@ -62,8 +62,11 @@ public abstract class AbstractStaxEventWriterItemWriterTests {
try {
writer.write(objects);
}
catch (RuntimeException e) {
throw e;
}
catch (Exception e) {
status.setRollbackOnly();
throw new IllegalStateException("Exception encountered on write", e);
}
return null;
}
@@ -73,22 +76,26 @@ public abstract class AbstractStaxEventWriterItemWriterTests {
stopWatch.stop();
logger.info("Timing for XML writer: " + stopWatch);
XMLUnit.setIgnoreWhitespace(true);
// String content = FileUtils.readFileToString(resource.getFile());
// System.err.println(content);
XMLAssert.assertXMLEqual(new FileReader(expected.getFile()), new FileReader(resource.getFile()));
}
@Before
public void setUp() throws Exception {
// File outputFile =
// File.createTempFile("AbstractStaxStreamWriterOutputSourceTests",
// "xml");
outputFile = File.createTempFile(ClassUtils.getShortName(this.getClass()), ".xml");
File directory = new File("target/data");
directory.mkdirs();
outputFile = File.createTempFile(ClassUtils.getShortName(this.getClass()), ".xml", directory);
resource = new FileSystemResource(outputFile);
writer.setResource(resource);
writer.setMarshaller(getMarshaller());
writer.afterPropertiesSet();
writer.open(new ExecutionContext());
}
@After

View File

@@ -0,0 +1,45 @@
package org.springframework.batch.io.oxm;
import static org.junit.Assert.assertTrue;
import java.io.StringWriter;
import java.math.BigDecimal;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import org.springframework.batch.io.oxm.domain.Trade;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
public class Jaxb2MarshallingTests extends AbstractStaxEventWriterItemWriterTests {
protected Marshaller getMarshaller() throws Exception {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(new Class<?>[] { Trade.class });
marshaller.afterPropertiesSet();
StringWriter string = new StringWriter();
marshaller.marshal(new Trade("FOO", 100, BigDecimal.valueOf(10.), "bar"), new StreamResult(string));
String content = string.toString();
assertTrue("Wrong content: "+content, content.contains("<customer>bar</customer>"));
return marshaller;
}
public static String getTextFromSource(Source source) {
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StreamResult stream = new StreamResult(new StringWriter());
transformer.transform(source, stream);
return stream.getWriter().toString();
}
catch (Exception e) {
throw new IllegalStateException(e);
}
}
}

View File

@@ -0,0 +1,128 @@
package org.springframework.batch.io.oxm;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileReader;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.custommonkey.xmlunit.XMLAssert;
import org.custommonkey.xmlunit.XMLUnit;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.io.oxm.domain.QualifiedTrade;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.xml.StaxEventItemWriter;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.ClassUtils;
import org.springframework.util.StopWatch;
public class Jaxb2NamespaceMarshallingTests {
private Log logger = LogFactory.getLog(getClass());
private static final int MAX_WRITE = 100;
private StaxEventItemWriter<QualifiedTrade> writer = new StaxEventItemWriter<QualifiedTrade>();
private Resource resource;
private File outputFile;
private Resource expected = new ClassPathResource("expected-qualified-output.xml", getClass());
private List<QualifiedTrade> objects = new ArrayList<QualifiedTrade>() {
{
add(new QualifiedTrade("isin1", 1, new BigDecimal(1.0), "customer1"));
add(new QualifiedTrade("isin2", 2, new BigDecimal(2.0), "customer2"));
add(new QualifiedTrade("isin3", 3, new BigDecimal(3.0), "customer3"));
}
};
/**
* Write list of domain objects and check the output file.
*/
@Test
public void testWrite() throws Exception {
StopWatch stopWatch = new StopWatch(getClass().getSimpleName());
stopWatch.start();
for (int i = 0; i < MAX_WRITE; i++) {
new TransactionTemplate(new ResourcelessTransactionManager()).execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
try {
writer.write(objects);
}
catch (RuntimeException e) {
throw e;
}
catch (Exception e) {
throw new IllegalStateException("Exception encountered on write", e);
}
return null;
}
});
}
writer.close();
stopWatch.stop();
logger.info("Timing for XML writer: " + stopWatch);
XMLUnit.setIgnoreWhitespace(true);
// String content = FileUtils.readFileToString(resource.getFile());
// System.err.println(content);
XMLAssert.assertXMLEqual(new FileReader(expected.getFile()), new FileReader(resource.getFile()));
}
@Before
public void setUp() throws Exception {
File directory = new File("target/data");
directory.mkdirs();
outputFile = File.createTempFile(ClassUtils.getShortName(this.getClass()), ".xml", directory);
resource = new FileSystemResource(outputFile);
writer.setResource(resource);
writer.setMarshaller(getMarshaller());
writer.setRootTagName("{urn:org.springframework.batch.io.oxm.domain}trades");
writer.afterPropertiesSet();
writer.open(new ExecutionContext());
}
@After
public void tearDown() throws Exception {
outputFile.delete();
}
protected Marshaller getMarshaller() throws Exception {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(new Class<?>[] { QualifiedTrade.class });
marshaller.afterPropertiesSet();
StringWriter string = new StringWriter();
marshaller.marshal(new QualifiedTrade("FOO", 100, BigDecimal.valueOf(10.), "bar"), new StreamResult(string));
String content = string.toString();
assertTrue("Wrong content: "+content, content.contains("<customer>bar</customer>"));
return marshaller;
}
}

View File

@@ -0,0 +1,108 @@
package org.springframework.batch.io.oxm;
import static org.junit.Assert.assertEquals;
import java.io.StringReader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import javax.xml.transform.stream.StreamSource;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.io.oxm.domain.QualifiedTrade;
import org.springframework.batch.io.oxm.domain.Trade;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.xml.StaxEventItemReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
public class Jaxb2NamespaceUnmarshallingTests {
private StaxEventItemReader<QualifiedTrade> reader = new StaxEventItemReader<QualifiedTrade>();
private Resource resource = new ClassPathResource("org/springframework/batch/io/oxm/domain/trades.xml");
@Before
public void setUp() throws Exception {
reader.setResource(resource);
reader.setFragmentRootElementName("{urn:org.springframework.batch.io.oxm.domain}trade");
reader.setUnmarshaller(getUnmarshaller());
reader.afterPropertiesSet();
reader.open(new ExecutionContext());
}
@Test
public void testUnmarshal() throws Exception {
QualifiedTrade trade = (QualifiedTrade) getUnmarshaller().unmarshal(new StreamSource(new StringReader(TRADE_XML)));
assertEquals("XYZ0001", trade.getIsin());
assertEquals(5, trade.getQuantity());
assertEquals(new BigDecimal("11.39"), trade.getPrice());
assertEquals("Customer1", trade.getCustomer());
}
@Test
public void testRead() throws Exception {
QualifiedTrade result;
List<QualifiedTrade> results = new ArrayList<QualifiedTrade>();
while ((result = reader.read()) != null) {
results.add(result);
}
checkResults(results);
}
protected Unmarshaller getUnmarshaller() throws Exception {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(new Class<?>[] { QualifiedTrade.class });
marshaller.setSchema(new ClassPathResource("trade.xsd", Trade.class));
marshaller.afterPropertiesSet();
return marshaller;
}
/**
* @param results list of domain objects returned by input source
*/
protected void checkResults(List<QualifiedTrade> results) {
assertEquals(3, results.size());
QualifiedTrade trade1 = results.get(0);
assertEquals("XYZ0001", trade1.getIsin());
assertEquals(5, trade1.getQuantity());
assertEquals(new BigDecimal("11.39"), trade1.getPrice());
assertEquals("Customer1", trade1.getCustomer());
QualifiedTrade trade2 = results.get(1);
assertEquals("XYZ0002", trade2.getIsin());
assertEquals(2, trade2.getQuantity());
assertEquals(new BigDecimal("72.99"), trade2.getPrice());
assertEquals("Customer2", trade2.getCustomer());
QualifiedTrade trade3 = results.get(2);
assertEquals("XYZ0003", trade3.getIsin());
assertEquals(9, trade3.getQuantity());
assertEquals(new BigDecimal("99.99"), trade3.getPrice());
assertEquals("Customer3", trade3.getCustomer());
}
@After
public void tearDown() throws Exception {
reader.close();
}
private static String TRADE_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><trade xmlns=\"urn:org.springframework.batch.io.oxm.domain\">"
+ "<customer>Customer1</customer><isin>XYZ0001</isin><price>11.39</price><quantity>5</quantity>"
+ "</trade>";
}

View File

@@ -0,0 +1,20 @@
package org.springframework.batch.io.oxm;
import org.springframework.batch.io.oxm.domain.Trade;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
public class Jaxb2UnmarshallingTests extends AbstractStaxEventReaderItemReaderTests {
protected Unmarshaller getUnmarshaller() throws Exception {
reader.setFragmentRootElementName("trade");
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setClassesToBeBound(new Class<?>[] { Trade.class });
// marshaller.setSchema(new ClassPathResource("trade.xsd", Trade.class));
marshaller.afterPropertiesSet();
return marshaller;
}
}

View File

@@ -0,0 +1,121 @@
package org.springframework.batch.io.oxm.domain;
import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* @author Rob Harrop
*/
@XmlRootElement(name="trade", namespace="urn:org.springframework.batch.io.oxm.domain")
@XmlType
@XmlAccessorType(XmlAccessType.FIELD)
public class QualifiedTrade {
@XmlElement(namespace="urn:org.springframework.batch.io.oxm.domain")
private String isin = "";
@XmlElement(namespace="urn:org.springframework.batch.io.oxm.domain")
private long quantity = 0;
@XmlElement(namespace="urn:org.springframework.batch.io.oxm.domain")
private BigDecimal price = new BigDecimal(0);
@XmlElement(namespace="urn:org.springframework.batch.io.oxm.domain")
private String customer = "";
public QualifiedTrade() {
}
public QualifiedTrade(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 + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((customer == null) ? 0 : customer.hashCode());
result = prime * result + ((isin == null) ? 0 : isin.hashCode());
result = prime * result + ((price == null) ? 0 : price.hashCode());
result = prime * result + (int) (quantity ^ (quantity >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
QualifiedTrade other = (QualifiedTrade) obj;
if (customer == null) {
if (other.customer != null)
return false;
}
else if (!customer.equals(other.customer))
return false;
if (isin == null) {
if (other.isin != null)
return false;
}
else if (!isin.equals(other.isin))
return false;
if (price == null) {
if (other.price != null)
return false;
}
else if (!price.equals(other.price))
return false;
if (quantity != other.quantity)
return false;
return true;
}
}

View File

@@ -2,9 +2,14 @@ package org.springframework.batch.io.oxm.domain;
import java.math.BigDecimal;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* @author Rob Harrop
*/
@XmlRootElement(name="trade")
@XmlType
public class Trade {
private String isin = "";

View File

@@ -9,4 +9,5 @@ log4j.category.org.apache.activemq=ERROR
log4j.category.org.springframework.jdbc=DEBUG
log4j.category.org.springframework.jms=DEBUG
log4j.category.org.springframework.batch=DEBUG
log4j.category.org.springframework.batch.support=INFO
log4j.category.org.springframework.retry=DEBUG

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" targetNamespace="urn:org.springframework.batch.io.oxm.domain"
xmlns:tns="urn:org.springframework.batch.io.oxm.domain" xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xs:element name="trades">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded"><xs:element name="trade" type="tns:trade"/></xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="trade" type="tns:trade"/>
<xs:complexType name="trade">
<xs:sequence>
<xs:element name="customer" type="xs:string" minOccurs="0"/>
<xs:element name="isin" type="xs:string" minOccurs="0"/>
<xs:element name="price" type="xs:decimal" minOccurs="0"/>
<xs:element name="quantity" type="xs:long"/>
</xs:sequence>
</xs:complexType>
</xs:schema>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<trades xmlns="urn:org.springframework.batch.io.oxm.domain" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:org.springframework.batch.io.oxm.domain trade.xsd">
<trade>
<customer>Customer1</customer>
<isin>XYZ0001</isin>
<price>11.39</price>
<quantity>5</quantity>
</trade>
<trade>
<customer>Customer2</customer>
<isin>XYZ0002</isin>
<price>72.99</price>
<quantity>2</quantity>
</trade>
<trade>
<customer>Customer3</customer>
<isin>XYZ0003</isin>
<price>99.99</price>
<quantity>9</quantity>
</trade>
</trades>