Skip to content

Commit e4651d6

Browse files
committed
XmlEventDecoder uses common defensive XMLInputFactory (now in StaxUtils)
Issue: SPR-15797
1 parent 40df7b6 commit e4651d6

File tree

5 files changed

+50
-60
lines changed

5 files changed

+50
-60
lines changed

spring-core/src/main/java/org/springframework/util/xml/StaxUtils.java

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import javax.xml.stream.XMLEventFactory;
2121
import javax.xml.stream.XMLEventReader;
2222
import javax.xml.stream.XMLEventWriter;
23+
import javax.xml.stream.XMLInputFactory;
24+
import javax.xml.stream.XMLResolver;
2325
import javax.xml.stream.XMLStreamException;
2426
import javax.xml.stream.XMLStreamReader;
2527
import javax.xml.stream.XMLStreamWriter;
@@ -33,20 +35,40 @@
3335
import org.xml.sax.XMLReader;
3436

3537
import org.springframework.lang.Nullable;
38+
import org.springframework.util.StreamUtils;
3639

3740
/**
38-
* Convenience methods for working with the StAX API. Partly historic due to JAXP 1.3 compatibility;
39-
* as of Spring 4.0, relying on JAXP 1.4 as included in JDK 1.6 and higher.
41+
* Convenience methods for working with the StAX API. Partly historic due to JAXP 1.3
42+
* compatibility; as of Spring 4.0, relying on JAXP 1.4 as included in JDK 1.6 and higher.
4043
*
41-
* <p>In particular, methods for using StAX ({@code javax.xml.stream}) in combination with the TrAX API
42-
* ({@code javax.xml.transform}), and converting StAX readers/writers into SAX readers/handlers and vice-versa.
44+
* <p>In particular, methods for using StAX ({@code javax.xml.stream}) in combination with
45+
* the TrAX API ({@code javax.xml.transform}), and converting StAX readers/writers into SAX
46+
* readers/handlers and vice-versa.
4347
*
4448
* @author Arjen Poutsma
4549
* @author Juergen Hoeller
4650
* @since 3.0
4751
*/
4852
public abstract class StaxUtils {
4953

54+
private static final XMLResolver NO_OP_XML_RESOLVER =
55+
(publicID, systemID, base, ns) -> StreamUtils.emptyInput();
56+
57+
58+
/**
59+
* Create an {@link XMLInputFactory} with Spring's defensive setup,
60+
* i.e. no support for the resolution of DTDs and external entities.
61+
* @return a new input factory to use
62+
* @since 5.0
63+
*/
64+
public static XMLInputFactory createDefensiveInputFactory() {
65+
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
66+
inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
67+
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
68+
inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
69+
return inputFactory;
70+
}
71+
5072
/**
5173
* Create a JAXP 1.4 {@link StAXSource} for the given {@link XMLStreamReader}.
5274
* @param streamReader the StAX stream reader
@@ -57,7 +79,7 @@ public static Source createStaxSource(XMLStreamReader streamReader) {
5779
}
5880

5981
/**
60-
* Create a JAXP 1.4 a {@link StAXSource} for the given {@link XMLEventReader}.
82+
* Create a JAXP 1.4 {@link StAXSource} for the given {@link XMLEventReader}.
6183
* @param eventReader the StAX event reader
6284
* @return a source wrapping the {@code eventReader}
6385
*/

spring-web/src/main/java/org/springframework/http/codec/xml/XmlEventDecoder.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.springframework.util.ClassUtils;
4545
import org.springframework.util.MimeType;
4646
import org.springframework.util.MimeTypeUtils;
47+
import org.springframework.util.xml.StaxUtils;
4748

4849
/**
4950
* Decodes a {@link DataBuffer} stream into a stream of {@link XMLEvent}s.
@@ -77,7 +78,7 @@
7778
*/
7879
public class XmlEventDecoder extends AbstractDecoder<XMLEvent> {
7980

80-
private static final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
81+
private static final XMLInputFactory inputFactory = StaxUtils.createDefensiveInputFactory();
8182

8283
private static final boolean aaltoPresent = ClassUtils.isPresent(
8384
"com.fasterxml.aalto.AsyncXMLStreamReader", XmlEventDecoder.class.getClassLoader());

spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@
2626
import java.util.Locale;
2727
import java.util.Map;
2828
import java.util.TimeZone;
29-
import javax.xml.stream.XMLInputFactory;
30-
import javax.xml.stream.XMLResolver;
3129

3230
import com.fasterxml.jackson.annotation.JsonFilter;
3331
import com.fasterxml.jackson.annotation.JsonInclude;
@@ -62,8 +60,8 @@
6260
import org.springframework.lang.Nullable;
6361
import org.springframework.util.Assert;
6462
import org.springframework.util.ClassUtils;
65-
import org.springframework.util.StreamUtils;
6663
import org.springframework.util.StringUtils;
64+
import org.springframework.util.xml.StaxUtils;
6765

6866
/**
6967
* A builder used to create {@link ObjectMapper} instances with a fluent API.
@@ -827,38 +825,27 @@ public static Jackson2ObjectMapperBuilder cbor() {
827825
private static class XmlObjectMapperInitializer {
828826

829827
public ObjectMapper create() {
830-
return new XmlMapper(xmlInputFactory());
828+
return new XmlMapper(StaxUtils.createDefensiveInputFactory());
831829
}
832830

833831
public ObjectMapper create(boolean defaultUseWrapper) {
834832
JacksonXmlModule module = new JacksonXmlModule();
835833
module.setDefaultUseWrapper(defaultUseWrapper);
836-
return new XmlMapper(new XmlFactory(xmlInputFactory()), module);
834+
return new XmlMapper(new XmlFactory(StaxUtils.createDefensiveInputFactory()), module);
837835
}
838-
839-
private static XMLInputFactory xmlInputFactory() {
840-
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
841-
inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
842-
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
843-
inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
844-
return inputFactory;
845-
}
846-
847-
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
848-
@Override
849-
public Object resolveEntity(String publicID, String systemID, String base, String ns) {
850-
return StreamUtils.emptyInput();
851-
}
852-
};
853836
}
854837

838+
855839
private static class SmileFactoryInitializer {
840+
856841
public JsonFactory create() {
857842
return new SmileFactory();
858843
}
859844
}
860845

846+
861847
private static class CborFactoryInitializer {
848+
862849
public JsonFactory create() {
863850
return new CBORFactory();
864851
}

spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import javax.xml.bind.annotation.XmlRootElement;
3232
import javax.xml.bind.annotation.XmlType;
3333
import javax.xml.stream.XMLInputFactory;
34-
import javax.xml.stream.XMLResolver;
3534
import javax.xml.stream.XMLStreamException;
3635
import javax.xml.stream.XMLStreamReader;
3736
import javax.xml.transform.Result;
@@ -47,7 +46,7 @@
4746
import org.springframework.http.converter.HttpMessageNotWritableException;
4847
import org.springframework.lang.Nullable;
4948
import org.springframework.util.ReflectionUtils;
50-
import org.springframework.util.StreamUtils;
49+
import org.springframework.util.xml.StaxUtils;
5150

5251
/**
5352
* An {@code HttpMessageConverter} that can read XML collections using JAXB2.
@@ -242,25 +241,15 @@ protected void writeToResult(T t, HttpHeaders headers, Result result) throws IOE
242241
}
243242

244243
/**
245-
* Create a {@code XMLInputFactory} that this converter will use to create {@link
246-
* javax.xml.stream.XMLStreamReader} and {@link javax.xml.stream.XMLEventReader} objects.
244+
* Create an {@code XMLInputFactory} that this converter will use to create
245+
* {@link javax.xml.stream.XMLStreamReader} and {@link javax.xml.stream.XMLEventReader}
246+
* objects.
247247
* <p>Can be overridden in subclasses, adding further initialization of the factory.
248248
* The resulting factory is cached, so this method will only be called once.
249+
* @see StaxUtils#createDefensiveInputFactory()
249250
*/
250251
protected XMLInputFactory createXmlInputFactory() {
251-
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
252-
inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
253-
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
254-
inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
255-
return inputFactory;
252+
return StaxUtils.createDefensiveInputFactory();
256253
}
257254

258-
259-
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
260-
@Override
261-
public Object resolveEntity(String publicID, String systemID, String base, String ns) {
262-
return StreamUtils.emptyInput();
263-
}
264-
};
265-
266255
}

spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -66,7 +66,13 @@
6666
*/
6767
public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMessageConverter<T> {
6868

69-
private static final Set<Class<?>> SUPPORTED_CLASSES = new HashSet<>(5);
69+
private static final EntityResolver NO_OP_ENTITY_RESOLVER =
70+
(publicId, systemId) -> new InputSource(new StringReader(""));
71+
72+
private static final XMLResolver NO_OP_XML_RESOLVER =
73+
(publicID, systemID, base, ns) -> StreamUtils.emptyInput();
74+
75+
private static final Set<Class<?>> SUPPORTED_CLASSES = new HashSet<>(8);
7076

7177
static {
7278
SUPPORTED_CLASSES.add(DOMSource.class);
@@ -279,19 +285,4 @@ public void write(byte[] b, int off, int len) throws IOException {
279285
}
280286
}
281287

282-
283-
private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
284-
@Override
285-
public InputSource resolveEntity(String publicId, String systemId) {
286-
return new InputSource(new StringReader(""));
287-
}
288-
};
289-
290-
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
291-
@Override
292-
public Object resolveEntity(String publicID, String systemID, String base, String ns) {
293-
return StreamUtils.emptyInput();
294-
}
295-
};
296-
297288
}

0 commit comments

Comments
 (0)