diff --git a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/xml/Jaxb2MarshallingTests.java b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/xml/Jaxb2MarshallingTests.java index 00e3d5296..b3f340b7a 100644 --- a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/xml/Jaxb2MarshallingTests.java +++ b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/item/xml/Jaxb2MarshallingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2010-2014 the original author or authors. + * Copyright 2010-2019 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. @@ -20,6 +20,7 @@ import static org.junit.Assert.assertTrue; import java.io.StringWriter; import java.math.BigDecimal; +import javax.xml.XMLConstants; import javax.xml.transform.OutputKeys; import javax.xml.transform.Source; import javax.xml.transform.Transformer; @@ -48,7 +49,10 @@ public class Jaxb2MarshallingTests extends AbstractStaxEventWriterItemWriterTest public static String getTextFromSource(Source source) { try { - Transformer transformer = TransformerFactory.newInstance().newTransformer(); + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + Transformer transformer = transformerFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); StreamResult stream = new StreamResult(new StringWriter()); transformer.transform(source, stream); 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 db225b9c4..b2da676ee 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 @@ -1,5 +1,5 @@ /* - * Copyright 2006-2007 the original author or authors. + * Copyright 2006-2019 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. @@ -54,6 +54,7 @@ import org.springframework.util.StringUtils; * The implementation is not thread-safe. * * @author Robert Kasanicky + * @author Mahmoud Ben Hassine */ public class StaxEventItemReader extends AbstractItemCountingItemStreamItemReader implements ResourceAwareItemReaderItemStream, InitializingBean { @@ -76,6 +77,8 @@ ResourceAwareItemReaderItemStream, InitializingBean { private boolean strict = true; + private XMLInputFactory xmlInputFactory = StaxUtils.createXmlInputFactory(); + public StaxEventItemReader() { setName(ClassUtils.getShortName(StaxEventItemReader.class)); } @@ -118,6 +121,15 @@ ResourceAwareItemReaderItemStream, InitializingBean { } } + /** + * Set the {@link XMLInputFactory}. + * @param xmlInputFactory to use + */ + public void setXmlInputFactory(XMLInputFactory xmlInputFactory) { + Assert.notNull(xmlInputFactory, "XMLInputFactory must not be null"); + this.xmlInputFactory = xmlInputFactory; + } + /** * Ensure that all required dependencies for the ItemReader to run are provided after all properties have been set. * @@ -208,7 +220,7 @@ ResourceAwareItemReaderItemStream, InitializingBean { } inputStream = resource.getInputStream(); - eventReader = XMLInputFactory.newInstance().createXMLEventReader(inputStream); + eventReader = xmlInputFactory.createXMLEventReader(inputStream); fragmentReader = new DefaultFragmentEventReader(eventReader); noInput = false; diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxUtils.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxUtils.java index c274f0b3a..3122ab18f 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxUtils.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/xml/StaxUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2007 the original author or authors. + * Copyright 2006-2019 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. @@ -18,6 +18,7 @@ package org.springframework.batch.item.xml; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.transform.Result; import javax.xml.transform.Source; @@ -31,6 +32,7 @@ import javax.xml.transform.stax.StAXSource; * This class is thread-safe. * * @author Josh Long + * @author Mahmoud Ben Hassine * */ public abstract class StaxUtils { @@ -42,4 +44,11 @@ public abstract class StaxUtils { public static Result getResult(XMLEventWriter w) { return new StAXResult(w); } + + public static XMLInputFactory createXmlInputFactory() { + XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance(); + xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false); + xmlInputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); + return xmlInputFactory; + } } 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 f97798c6a..deaba19a1 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 @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2019 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. @@ -19,7 +19,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import javax.xml.stream.XMLInputFactory; + import org.springframework.batch.item.xml.StaxEventItemReader; +import org.springframework.batch.item.xml.StaxUtils; import org.springframework.core.io.Resource; import org.springframework.oxm.Unmarshaller; import org.springframework.util.Assert; @@ -50,6 +53,8 @@ public class StaxEventItemReaderBuilder { private int currentItemCount; + private XMLInputFactory xmlInputFactory = StaxUtils.createXmlInputFactory(); + /** * Configure if the state of the {@link org.springframework.batch.item.ItemStreamSupport} * should be persisted within the {@link org.springframework.batch.item.ExecutionContext} @@ -175,6 +180,19 @@ public class StaxEventItemReaderBuilder { return this; } + /** + * Set the {@link XMLInputFactory}. + * + * @param xmlInputFactory to use + * @return The current instance of the builder + * @see StaxEventItemReader#setXmlInputFactory(XMLInputFactory) + */ + public StaxEventItemReaderBuilder xmlInputFactory(XMLInputFactory xmlInputFactory) { + this.xmlInputFactory = xmlInputFactory; + + return this; + } + /** * Validates the configuration and builds a new {@link StaxEventItemReader} * @@ -203,6 +221,7 @@ public class StaxEventItemReaderBuilder { reader.setUnmarshaller(this.unmarshaller); reader.setCurrentItemCount(this.currentItemCount); reader.setMaxItemCount(this.maxItemCount); + reader.setXmlInputFactory(this.xmlInputFactory); 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 a33905ebf..1a92b6a24 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 @@ -1,5 +1,5 @@ /* - * Copyright 2008-2014 the original author or authors. + * Copyright 2008-2019 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. @@ -15,6 +15,8 @@ */ package org.springframework.batch.item.xml; +import org.hamcrest.Matchers; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.batch.item.ExecutionContext; @@ -33,12 +35,12 @@ import org.springframework.util.ClassUtils; import javax.xml.namespace.QName; import javax.xml.stream.FactoryConfigurationError; import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.EndElement; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import javax.xml.transform.Source; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -56,6 +58,8 @@ import static org.junit.Assert.fail; * Tests for {@link StaxEventItemReader}. * * @author Robert Kasanicky + * @author Michael Minella + * @author Mahmoud Ben Hassine */ public class StaxEventItemReaderTests { @@ -329,7 +333,7 @@ public class StaxEventItemReaderTests { @Test public void testMoveCursorToNextFragment() throws XMLStreamException, FactoryConfigurationError, IOException { Resource resource = new ByteArrayResource(xml.getBytes()); - XMLEventReader reader = XMLInputFactory.newInstance().createXMLEventReader(resource.getInputStream()); + XMLEventReader reader = StaxUtils.createXmlInputFactory().createXMLEventReader(resource.getInputStream()); final int EXPECTED_NUMBER_OF_FRAGMENTS = 2; for (int i = 0; i < EXPECTED_NUMBER_OF_FRAGMENTS; i++) { @@ -346,7 +350,7 @@ public class StaxEventItemReaderTests { @Test public void testMoveCursorToNextFragmentOnEmpty() throws XMLStreamException, FactoryConfigurationError, IOException { Resource resource = new ByteArrayResource(emptyXml.getBytes()); - XMLEventReader reader = XMLInputFactory.newInstance().createXMLEventReader(resource.getInputStream()); + XMLEventReader reader = StaxUtils.createXmlInputFactory().createXMLEventReader(resource.getInputStream()); assertFalse(source.moveCursorToNextFragment(reader)); } @@ -357,7 +361,7 @@ public class StaxEventItemReaderTests { @Test public void testMoveCursorToNextFragmentOnMissing() throws XMLStreamException, FactoryConfigurationError, IOException { Resource resource = new ByteArrayResource(missingXml.getBytes()); - XMLEventReader reader = XMLInputFactory.newInstance().createXMLEventReader(resource.getInputStream()); + XMLEventReader reader = StaxUtils.createXmlInputFactory().createXMLEventReader(resource.getInputStream()); assertFalse(source.moveCursorToNextFragment(reader)); } @@ -577,6 +581,39 @@ public class StaxEventItemReaderTests { assertNull(source.read()); } + @Test + public void testDtdXml() { + String xmlWithDtd = "\n\n]>\n&entityex;"; + StaxEventItemReader reader = new StaxEventItemReader<>(); + reader.setName("foo"); + reader.setResource(new ByteArrayResource(xmlWithDtd.getBytes())); + reader.setUnmarshaller(new MockFragmentUnmarshaller() { + @Override + public Object unmarshal(Source source) throws XmlMappingException { + try { + XMLEventReader xmlEventReader = StaxTestUtils.getXmlEventReader(source); + xmlEventReader.nextEvent(); + xmlEventReader.nextEvent(); + return xmlEventReader.getElementText(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + reader.setFragmentRootElementName("abc"); + + reader.open(new ExecutionContext()); + + try { + reader.read(); + fail("Should fail when XML contains DTD"); + } catch (Exception e) { + Assert.assertThat(e.getMessage(), Matchers.containsString("Undeclared general entity \"entityex\"")); + } + } + /** * Stub emulating problems during unmarshalling. */ 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 ff7d16db8..c73ff7645 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 @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2017-2019 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. @@ -16,6 +16,7 @@ package org.springframework.batch.item.xml.builder; import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.stream.XMLInputFactory; import org.junit.Before; import org.junit.Test; @@ -35,6 +36,7 @@ import static org.junit.Assert.fail; /** * @author Michael Minella + * @author Mahmoud Ben Hassine */ public class StaxEventItemReaderBuilderTests { @@ -95,6 +97,7 @@ public class StaxEventItemReaderBuilderTests { .currentItemCount(1) .maxItemCount(2) .unmarshaller(unmarshaller) + .xmlInputFactory(XMLInputFactory.newInstance()) .build(); reader.afterPropertiesSet(); diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/stax/DefaultFragmentEventReaderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/stax/DefaultFragmentEventReaderTests.java index 8e1717ae2..719e9d4fd 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/stax/DefaultFragmentEventReaderTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/xml/stax/DefaultFragmentEventReaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2012 the original author or authors. + * Copyright 2008-2019 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. @@ -18,13 +18,13 @@ package org.springframework.batch.item.xml.stax; import java.util.NoSuchElementException; import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.XMLEvent; import junit.framework.TestCase; import org.springframework.batch.item.xml.EventHelper; +import org.springframework.batch.item.xml.StaxUtils; import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.Resource; @@ -32,6 +32,7 @@ import org.springframework.core.io.Resource; * Tests for {@link DefaultFragmentEventReader}. * * @author Robert Kasanicky + * @author Mahmoud Ben Hassine */ public class DefaultFragmentEventReaderTests extends TestCase { @@ -50,7 +51,7 @@ public class DefaultFragmentEventReaderTests extends TestCase { @Override protected void setUp() throws Exception { Resource input = new ByteArrayResource(xml.getBytes()); - eventReader = XMLInputFactory.newInstance().createXMLEventReader( + eventReader = StaxUtils.createXmlInputFactory().createXMLEventReader( input.getInputStream()); fragmentReader = new DefaultFragmentEventReader(eventReader); }