From 3f12a0f9a455395b636e57c39db2d827d75bb773 Mon Sep 17 00:00:00 2001 From: jpraet Date: Fri, 1 Mar 2013 20:25:11 +0100 Subject: [PATCH 1/2] BATCH-1975: StaxEventItemWriter namespace added to elements after restart --- .../batch/item/xml/StaxEventItemWriter.java | 34 +++++++ .../item/xml/StaxEventItemWriterTests.java | 99 ++++++++++++++++++- 2 files changed, 131 insertions(+), 2 deletions(-) diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java index 782191cbf..f5b659fe8 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java @@ -438,6 +438,7 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl } delegateEventWriter = createXmlEventWriter(outputFactory, bufferedWriter); eventWriter = new NoStartEndDocumentStreamWriter(delegateEventWriter); + initNamespaceContext(delegateEventWriter); if (!restarted) { startDocument(delegateEventWriter); } @@ -491,6 +492,39 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl protected Result createStaxResult() throws Exception { return StaxUtils.getResult(eventWriter); } + + /** + * Inits the namespace context of the XMLEventWriter: + *
    + *
  • rootTagNamespacePrefix for rootTagName
  • + *
  • any other xmlns namespace prefix declarations in the root element attributes
  • + *
+ * + * @param writer XML event writer + * @throws XMLStreamException + */ + protected void initNamespaceContext(XMLEventWriter writer) throws XMLStreamException { + if (StringUtils.hasText(getRootTagNamespace())) { + if(StringUtils.hasText(getRootTagNamespacePrefix())) { + writer.setPrefix(getRootTagNamespacePrefix(), getRootTagNamespace()); + } else { + writer.setDefaultNamespace(getRootTagNamespace()); + } + } + if (!CollectionUtils.isEmpty(getRootElementAttributes())) { + for (Map.Entry entry : getRootElementAttributes().entrySet()) { + String key = entry.getKey(); + if (key.startsWith("xmlns")) { + String prefix = ""; + if (key.contains(":")) { + prefix = key.substring(key.indexOf(":") + 1); + } + System.err.println("registering prefix: " +prefix + "=" + entry.getValue()); + writer.setPrefix(prefix, entry.getValue()); + } + } + } + } /** * Writes simple XML header containing: diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemWriterTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemWriterTests.java index 9e505eed6..4194cdc30 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemWriterTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemWriterTests.java @@ -12,6 +12,7 @@ import java.io.IOException; import java.util.Collections; import java.util.List; +import javax.xml.bind.annotation.XmlRootElement; import javax.xml.stream.XMLEventFactory; import javax.xml.stream.XMLEventWriter; import javax.xml.stream.XMLStreamException; @@ -27,6 +28,7 @@ import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.Resource; import org.springframework.oxm.Marshaller; import org.springframework.oxm.XmlMappingException; +import org.springframework.oxm.jaxb.Jaxb2Marshaller; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; @@ -55,8 +57,12 @@ public class StaxEventItemWriterTests { return ClassUtils.getShortName(StaxEventItemWriter.class) + "-testString"; } }; + + private JAXBItem jaxbItem = new JAXBItem(); private List items = Collections.singletonList(item); + + private List jaxbItems = Collections.singletonList(jaxbItem); private static final String TEST_STRING = "<" + ClassUtils.getShortName(StaxEventItemWriter.class) + "-testString/>"; @@ -68,6 +74,8 @@ public class StaxEventItemWriterTests { + "-testString/>"; private SimpleMarshaller marshaller; + + private Jaxb2Marshaller jaxbMarshaller; @Before public void setUp() throws Exception { @@ -76,6 +84,8 @@ public class StaxEventItemWriterTests { resource = new FileSystemResource(File.createTempFile("StaxEventWriterOutputSourceTests", ".xml", directory)); writer = createItemWriter(); executionContext = new ExecutionContext(); + jaxbMarshaller = new Jaxb2Marshaller(); + jaxbMarshaller.setClassesToBeBound(JAXBItem.class); } /** @@ -198,7 +208,6 @@ public class StaxEventItemWriterTests { // expected } writer.close(); - System.err.println(getOutputFileContent()); String outputFile = getOutputFileContent(); assertEquals("", outputFile); @@ -224,7 +233,6 @@ public class StaxEventItemWriterTests { // check the output is concatenation of 'before restart' and 'after // restart' writes. outputFile = getOutputFileContent(); - System.err.println(getOutputFileContent()); assertEquals(1, StringUtils.countOccurrencesOf(outputFile, TEST_STRING)); assertTrue(outputFile.contains("" + TEST_STRING + "")); assertEquals("", outputFile); @@ -401,6 +409,89 @@ public class StaxEventItemWriterTests { assertTrue("Wrong content: " + content, content.contains((""))); assertTrue("Wrong content: " + content, content.contains(("", content); + } + + /** + * Namespace prefixes are properly initialized on restart. + */ + @Test + public void testRootTagWithNamespaceAndPrefixRestart() throws Exception { + writer.setMarshaller(jaxbMarshaller); + writer.setRootTagName("{http://www.springframework.org/test}ns:root"); + writer.afterPropertiesSet(); + writer.open(executionContext); + writer.write(jaxbItems); + writer.update(executionContext); + writer.close(); + + writer = createItemWriter(); + writer.setMarshaller(jaxbMarshaller); + writer.setRootTagName("{http://www.springframework.org/test}ns:root"); + writer.afterPropertiesSet(); + writer.open(executionContext); + writer.write(jaxbItems); + writer.update(executionContext); + writer.close(); + + String content = getOutputFileContent(); + assertEquals("Wrong content: " + content, + "", content); + } + + /** + * Namespace prefixes are properly initialized on restart. + */ + @Test + public void testRootTagWithAdditionalNamespaceRestart() throws Exception { + writer.setMarshaller(jaxbMarshaller); + writer.setRootTagName("{urn:org.test.foo}foo:root"); + writer.setRootElementAttributes(Collections.singletonMap("xmlns:ns", "http://www.springframework.org/test")); + writer.afterPropertiesSet(); + writer.open(executionContext); + writer.write(jaxbItems); + writer.update(executionContext); + writer.close(); + + writer = createItemWriter(); + writer.setMarshaller(jaxbMarshaller); + writer.setRootTagName("{urn:org.test.foo}foo:root"); + writer.setRootElementAttributes(Collections.singletonMap("xmlns:ns", "http://www.springframework.org/test")); + writer.afterPropertiesSet(); + writer.open(executionContext); + writer.write(jaxbItems); + writer.update(executionContext); + writer.close(); + + String content = getOutputFileContent(); + assertEquals("Wrong content: " + content, + "", content); + } /** * Writes object's toString representation as XML comment. @@ -467,5 +558,9 @@ public class StaxEventItemWriterTests { return source; } + + @XmlRootElement(name="item", namespace="http://www.springframework.org/test") + private static class JAXBItem { + } } From 39c5e221f8b961f81afd98695c1b408761151ab4 Mon Sep 17 00:00:00 2001 From: Michael Minella Date: Mon, 4 Mar 2013 16:18:22 -0600 Subject: [PATCH 2/2] BATCH-1975: Minor cleanup --- .../batch/item/xml/StaxEventItemWriter.java | 39 +++++------ .../item/xml/StaxEventItemWriterTests.java | 64 ++++++++++--------- 2 files changed, 53 insertions(+), 50 deletions(-) diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java index f5b659fe8..4e8e351f3 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemWriter.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2012 the original author or authors. + * Copyright 2006-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -70,7 +70,7 @@ import org.springframework.util.StringUtils; * */ public class StaxEventItemWriter extends AbstractItemStreamItemWriter implements - ResourceAwareItemWriterItemStream, InitializingBean { +ResourceAwareItemWriterItemStream, InitializingBean { private static final Log log = LogFactory.getLog(StaxEventItemWriter.class); @@ -151,7 +151,7 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl * * @param resource the output file */ - @Override + @Override public void setResource(Resource resource) { this.resource = resource; } @@ -323,7 +323,7 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl * @throws Exception * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ - @Override + @Override public void afterPropertiesSet() throws Exception { Assert.notNull(marshaller); if (rootTagName.contains("{")) { @@ -341,10 +341,10 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl * * @see org.springframework.batch.item.ItemStream#open(ExecutionContext) */ - @Override + @Override public void open(ExecutionContext executionContext) { - super.open(executionContext); - + super.open(executionContext); + Assert.notNull(resource, "The resource must be set"); long startAtPosition = 0; @@ -375,6 +375,7 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl /** * Helper method for opening output source at given file position */ + @SuppressWarnings("resource") private void open(long position, boolean restarted) { File file; @@ -415,12 +416,12 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl final FileChannel channel = fileChannel; if (transactional) { TransactionAwareBufferedWriter writer = new TransactionAwareBufferedWriter(channel, new Runnable() { - @Override + @Override public void run() { closeStream(); } }); - + writer.setEncoding(encoding); bufferedWriter = writer; } @@ -492,7 +493,7 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl protected Result createStaxResult() throws Exception { return StaxUtils.getResult(eventWriter); } - + /** * Inits the namespace context of the XMLEventWriter: *
    @@ -506,7 +507,7 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl protected void initNamespaceContext(XMLEventWriter writer) throws XMLStreamException { if (StringUtils.hasText(getRootTagNamespace())) { if(StringUtils.hasText(getRootTagNamespacePrefix())) { - writer.setPrefix(getRootTagNamespacePrefix(), getRootTagNamespace()); + writer.setPrefix(getRootTagNamespacePrefix(), getRootTagNamespace()); } else { writer.setDefaultNamespace(getRootTagNamespace()); } @@ -519,11 +520,11 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl if (key.contains(":")) { prefix = key.substring(key.indexOf(":") + 1); } - System.err.println("registering prefix: " +prefix + "=" + entry.getValue()); + log.debug("registering prefix: " +prefix + "=" + entry.getValue()); writer.setPrefix(prefix, entry.getValue()); } } - } + } } /** @@ -609,10 +610,10 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl * * @see org.springframework.batch.item.ItemStream#close() */ - @Override + @Override public void close() { - super.close(); - + super.close(); + XMLEventFactory factory = createXmlEventFactory(); try { delegateEventWriter.add(factory.createCharacters("")); @@ -674,7 +675,7 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl * @throws IOException * @throws XmlMappingException */ - @Override + @Override public void write(List items) throws XmlMappingException, Exception { currentRecordCount += items.size(); @@ -699,9 +700,9 @@ public class StaxEventItemWriter extends AbstractItemStreamItemWriter impl * * @see org.springframework.batch.item.ItemStream#update(ExecutionContext) */ - @Override + @Override public void update(ExecutionContext executionContext) { - super.update(executionContext); + super.update(executionContext); if (saveState) { Assert.notNull(executionContext, "ExecutionContext must not be null"); executionContext.putLong(getExecutionContextKey(RESTART_DATA_NAME), getPosition()); diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemWriterTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemWriterTests.java index 4194cdc30..474935745 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemWriterTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemWriterTests.java @@ -1,11 +1,11 @@ package org.springframework.batch.item.xml; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.io.File; import java.io.IOException; @@ -52,16 +52,16 @@ public class StaxEventItemWriterTests { // test item for writing to output private Object item = new Object() { - @Override + @Override public String toString() { return ClassUtils.getShortName(StaxEventItemWriter.class) + "-testString"; } }; - + private JAXBItem jaxbItem = new JAXBItem(); private List items = Collections.singletonList(item); - + private List jaxbItems = Collections.singletonList(jaxbItem); private static final String TEST_STRING = "<" + ClassUtils.getShortName(StaxEventItemWriter.class) @@ -74,7 +74,7 @@ public class StaxEventItemWriterTests { + "-testString/>"; private SimpleMarshaller marshaller; - + private Jaxb2Marshaller jaxbMarshaller; @Before @@ -136,13 +136,14 @@ public class StaxEventItemWriterTests { } @Test + @SuppressWarnings({"unchecked", "rawtypes"}) public void testTransactionalRestart() throws Exception { writer.open(executionContext); PlatformTransactionManager transactionManager = new ResourcelessTransactionManager(); new TransactionTemplate(transactionManager).execute(new TransactionCallback() { - @Override + @Override public Object doInTransaction(TransactionStatus status) { try { // write item @@ -162,7 +163,7 @@ public class StaxEventItemWriterTests { writer = createItemWriter(); writer.open(executionContext); new TransactionTemplate(transactionManager).execute(new TransactionCallback() { - @Override + @Override public Object doInTransaction(TransactionStatus status) { try { writer.write(items); @@ -185,6 +186,7 @@ public class StaxEventItemWriterTests { } @Test + @SuppressWarnings({"unchecked", "rawtypes"}) public void testTransactionalRestartFailOnFirstWrite() throws Exception { PlatformTransactionManager transactionManager = new ResourcelessTransactionManager(); @@ -192,7 +194,7 @@ public class StaxEventItemWriterTests { writer.open(executionContext); try { new TransactionTemplate(transactionManager).execute(new TransactionCallback() { - @Override + @Override public Object doInTransaction(TransactionStatus status) { try { writer.write(items); @@ -214,7 +216,7 @@ public class StaxEventItemWriterTests { // create new writer from saved restart data and continue writing writer = createItemWriter(); new TransactionTemplate(transactionManager).execute(new TransactionCallback() { - @Override + @Override public Object doInTransaction(TransactionStatus status) { writer.open(executionContext); try { @@ -246,7 +248,7 @@ public class StaxEventItemWriterTests { writer.setHeaderCallback(new StaxWriterCallback() { - @Override + @Override public void write(XMLEventWriter writer) throws IOException { XMLEventFactory factory = XMLEventFactory.newInstance(); try { @@ -292,7 +294,7 @@ public class StaxEventItemWriterTests { public void testOpenAndClose() throws Exception { writer.setHeaderCallback(new StaxWriterCallback() { - @Override + @Override public void write(XMLEventWriter writer) throws IOException { XMLEventFactory factory = XMLEventFactory.newInstance(); try { @@ -308,7 +310,7 @@ public class StaxEventItemWriterTests { }); writer.setFooterCallback(new StaxWriterCallback() { - @Override + @Override public void write(XMLEventWriter writer) throws IOException { XMLEventFactory factory = XMLEventFactory.newInstance(); try { @@ -409,7 +411,7 @@ public class StaxEventItemWriterTests { assertTrue("Wrong content: " + content, content.contains((""))); assertTrue("Wrong content: " + content, content.contains(("", content); } - + /** * Namespace prefixes are properly initialized on restart. */ @@ -449,7 +451,7 @@ public class StaxEventItemWriterTests { writer.write(jaxbItems); writer.update(executionContext); writer.close(); - + writer = createItemWriter(); writer.setMarshaller(jaxbMarshaller); writer.setRootTagName("{http://www.springframework.org/test}ns:root"); @@ -458,12 +460,12 @@ public class StaxEventItemWriterTests { writer.write(jaxbItems); writer.update(executionContext); writer.close(); - + String content = getOutputFileContent(); - assertEquals("Wrong content: " + content, + assertEquals("Wrong content: " + content, "", content); - } - + } + /** * Namespace prefixes are properly initialized on restart. */ @@ -477,7 +479,7 @@ public class StaxEventItemWriterTests { writer.write(jaxbItems); writer.update(executionContext); writer.close(); - + writer = createItemWriter(); writer.setMarshaller(jaxbMarshaller); writer.setRootTagName("{urn:org.test.foo}foo:root"); @@ -487,11 +489,11 @@ public class StaxEventItemWriterTests { writer.write(jaxbItems); writer.update(executionContext); writer.close(); - + String content = getOutputFileContent(); - assertEquals("Wrong content: " + content, + assertEquals("Wrong content: " + content, "", content); - } + } /** * Writes object's toString representation as XML comment. @@ -510,9 +512,9 @@ public class StaxEventItemWriterTests { this.namespacePrefix = namespacePrefix; } - @Override + @Override public void marshal(Object graph, Result result) throws XmlMappingException, IOException { - Assert.isInstanceOf( Result.class, result); + Assert.isInstanceOf( Result.class, result); try { StaxUtils.getXmlEventWriter( result ).add( XMLEventFactory.newInstance().createStartElement(namespacePrefix, namespace, graph.toString())); StaxUtils.getXmlEventWriter( result ).add( XMLEventFactory.newInstance().createEndElement(namespacePrefix, namespace, graph.toString())); @@ -522,7 +524,7 @@ public class StaxEventItemWriterTests { } } - @Override + @Override @SuppressWarnings("rawtypes") public boolean supports(Class clazz) { return true; @@ -558,7 +560,7 @@ public class StaxEventItemWriterTests { return source; } - + @XmlRootElement(name="item", namespace="http://www.springframework.org/test") private static class JAXBItem { }