diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemReader.java index ee7598cfc5..80d170b77c 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxEventItemReader.java @@ -62,6 +62,8 @@ public class StaxEventItemReader extends AbstractItemCountingItemStreamItemRe private static final Log logger = LogFactory.getLog(StaxEventItemReader.class); + public static final String DEFAULT_ENCODING = "UTF-8"; + private FragmentEventReader fragmentReader; private XMLEventReader eventReader; @@ -80,6 +82,8 @@ public class StaxEventItemReader extends AbstractItemCountingItemStreamItemRe private XMLInputFactory xmlInputFactory = StaxUtils.createXmlInputFactory(); + private String encoding = DEFAULT_ENCODING; + public StaxEventItemReader() { setName(ClassUtils.getShortName(StaxEventItemReader.class)); } @@ -131,6 +135,16 @@ public void setXmlInputFactory(XMLInputFactory xmlInputFactory) { this.xmlInputFactory = xmlInputFactory; } + /** + * Set encoding to be used for input file. + * + * @param encoding the encoding to be used + */ + public void setEncoding(String encoding) { + Assert.notNull(encoding, "The encoding must not be null"); + this.encoding = encoding; + } + /** * Ensure that all required dependencies for the ItemReader to run are provided after all properties have been set. * @@ -221,7 +235,7 @@ protected void doOpen() throws Exception { } inputStream = resource.getInputStream(); - eventReader = xmlInputFactory.createXMLEventReader(inputStream); + eventReader = xmlInputFactory.createXMLEventReader(inputStream, this.encoding); fragmentReader = new DefaultFragmentEventReader(eventReader); noInput = false; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/builder/StaxEventItemReaderBuilder.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/builder/StaxEventItemReaderBuilder.java index d5e09beaf5..a84706b0f9 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/builder/StaxEventItemReaderBuilder.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/builder/StaxEventItemReaderBuilder.java @@ -33,6 +33,7 @@ * * @author Michael Minella * @author Glenn Renfro + * @author Mahmoud Ben Hassine * @since 4.0 */ public class StaxEventItemReaderBuilder { @@ -55,6 +56,8 @@ public class StaxEventItemReaderBuilder { private XMLInputFactory xmlInputFactory = StaxUtils.createXmlInputFactory(); + private String encoding = StaxEventItemReader.DEFAULT_ENCODING; + /** * Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport} * should be persisted within the {@link org.springframework.batch.item.ExecutionContext} @@ -193,6 +196,19 @@ public StaxEventItemReaderBuilder xmlInputFactory(XMLInputFactory xmlInputFac return this; } + /** + * Encoding for the input file. Defaults to UTF-8. + * + * @param encoding String encoding algorithm + * @return the current instance of the builder + * @see StaxEventItemReader#setEncoding(String) + */ + public StaxEventItemReaderBuilder encoding(String encoding) { + this.encoding = encoding; + + return this; + } + /** * Validates the configuration and builds a new {@link StaxEventItemReader} * @@ -222,6 +238,7 @@ public StaxEventItemReader build() { reader.setCurrentItemCount(this.currentItemCount); reader.setMaxItemCount(this.maxItemCount); reader.setXmlInputFactory(this.xmlInputFactory); + reader.setEncoding(this.encoding); return reader; } diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemReaderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemReaderTests.java index 8f4a9a1825..3fdeb7e085 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemReaderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/StaxEventItemReaderTests.java @@ -43,6 +43,9 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -146,6 +149,26 @@ public void testFragmentWrapping() throws Exception { source.close(); } + /** + * Regular usage scenario with custom encoding. + */ + @Test + public void testEncoding() throws Exception { + Charset encoding = StandardCharsets.ISO_8859_1; + ByteBuffer xmlResource = encoding.encode(xml); + source.setResource(new ByteArrayResource(xmlResource.array())); + source.setEncoding(encoding.toString()); + source.afterPropertiesSet(); + source.open(executionContext); + + // see asserts in the mock unmarshaller + assertNotNull(source.read()); + assertNotNull(source.read()); + assertNull(source.read()); // there are only two fragments + + source.close(); + } + @Test public void testItemCountAwareFragment() throws Exception { StaxEventItemReader source = createNewItemCountAwareInputSource(); diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/builder/StaxEventItemReaderBuilderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/builder/StaxEventItemReaderBuilderTests.java index 7d2355140a..91ae43fe8c 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/builder/StaxEventItemReaderBuilderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/builder/StaxEventItemReaderBuilderTests.java @@ -15,6 +15,8 @@ */ package org.springframework.batch.item.xml.builder; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.stream.XMLInputFactory; @@ -116,6 +118,40 @@ public void testConfiguration() throws Exception { assertEquals(2, executionContext.size()); } + @Test + public void testEncoding() throws Exception { + Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller(); + unmarshaller.setClassesToBeBound(Foo.class); + + ByteBuffer xml = StandardCharsets.ISO_8859_1.encode(SIMPLE_XML); + + StaxEventItemReader reader = new StaxEventItemReaderBuilder() + .name("fooReader") + .resource(new ByteArrayResource(xml.array())) + .encoding(StandardCharsets.ISO_8859_1.toString()) + .addFragmentRootElements("foo") + .currentItemCount(1) + .maxItemCount(2) + .unmarshaller(unmarshaller) + .xmlInputFactory(XMLInputFactory.newInstance()) + .build(); + + reader.afterPropertiesSet(); + + ExecutionContext executionContext = new ExecutionContext(); + reader.open(executionContext); + Foo item = reader.read(); + assertNull(reader.read()); + reader.update(executionContext); + + reader.close(); + + assertEquals(4, item.getFirst()); + assertEquals("five", item.getSecond()); + assertEquals("six", item.getThird()); + assertEquals(2, executionContext.size()); + } + @Test(expected = ItemStreamException.class) public void testStrict() throws Exception { Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller();