Avoid creation of SAXParserFactory for every read operation
Includes JAXBContext locking revision (avoiding synchronization) and consistent treatment of DocumentBuilderFactory (in terms of caching as well as locking). Closes gh-32851
This commit is contained in:
		
							parent
							
								
									f26483d272
								
							
						
					
					
						commit
						a4c2f291d9
					
				|  | @ -37,6 +37,8 @@ import java.util.Calendar; | ||||||
| import java.util.Date; | import java.util.Date; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
| import java.util.UUID; | import java.util.UUID; | ||||||
|  | import java.util.concurrent.locks.Lock; | ||||||
|  | import java.util.concurrent.locks.ReentrantLock; | ||||||
| 
 | 
 | ||||||
| import javax.xml.XMLConstants; | import javax.xml.XMLConstants; | ||||||
| import javax.xml.datatype.Duration; | import javax.xml.datatype.Duration; | ||||||
|  | @ -192,7 +194,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi | ||||||
| 	@Nullable | 	@Nullable | ||||||
| 	private ClassLoader beanClassLoader; | 	private ClassLoader beanClassLoader; | ||||||
| 
 | 
 | ||||||
| 	private final Object jaxbContextMonitor = new Object(); | 	private final Lock jaxbContextLock = new ReentrantLock(); | ||||||
| 
 | 
 | ||||||
| 	@Nullable | 	@Nullable | ||||||
| 	private volatile JAXBContext jaxbContext; | 	private volatile JAXBContext jaxbContext; | ||||||
|  | @ -204,6 +206,12 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi | ||||||
| 
 | 
 | ||||||
| 	private boolean processExternalEntities = false; | 	private boolean processExternalEntities = false; | ||||||
| 
 | 
 | ||||||
|  | 	@Nullable | ||||||
|  | 	private volatile SAXParserFactory schemaParserFactory; | ||||||
|  | 
 | ||||||
|  | 	@Nullable | ||||||
|  | 	private volatile SAXParserFactory sourceParserFactory; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Set multiple JAXB context paths. The given array of context paths gets | 	 * Set multiple JAXB context paths. The given array of context paths gets | ||||||
|  | @ -426,6 +434,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setSupportDtd(boolean supportDtd) { | 	public void setSupportDtd(boolean supportDtd) { | ||||||
| 		this.supportDtd = supportDtd; | 		this.supportDtd = supportDtd; | ||||||
|  | 		this.sourceParserFactory = null; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -450,6 +459,7 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi | ||||||
| 		if (processExternalEntities) { | 		if (processExternalEntities) { | ||||||
| 			this.supportDtd = true; | 			this.supportDtd = true; | ||||||
| 		} | 		} | ||||||
|  | 		this.sourceParserFactory = null; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -497,7 +507,9 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi | ||||||
| 		if (context != null) { | 		if (context != null) { | ||||||
| 			return context; | 			return context; | ||||||
| 		} | 		} | ||||||
| 		synchronized (this.jaxbContextMonitor) { | 
 | ||||||
|  | 		this.jaxbContextLock.lock(); | ||||||
|  | 		try { | ||||||
| 			context = this.jaxbContext; | 			context = this.jaxbContext; | ||||||
| 			if (context == null) { | 			if (context == null) { | ||||||
| 				try { | 				try { | ||||||
|  | @ -521,6 +533,9 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi | ||||||
| 			} | 			} | ||||||
| 			return context; | 			return context; | ||||||
| 		} | 		} | ||||||
|  | 		finally { | ||||||
|  | 			this.jaxbContextLock.unlock(); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private JAXBContext createJaxbContextFromContextPath(String contextPath) throws JAXBException { | 	private JAXBContext createJaxbContextFromContextPath(String contextPath) throws JAXBException { | ||||||
|  | @ -587,17 +602,24 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi | ||||||
| 		Assert.notEmpty(resources, "No resources given"); | 		Assert.notEmpty(resources, "No resources given"); | ||||||
| 		Assert.hasLength(schemaLanguage, "No schema language provided"); | 		Assert.hasLength(schemaLanguage, "No schema language provided"); | ||||||
| 		Source[] schemaSources = new Source[resources.length]; | 		Source[] schemaSources = new Source[resources.length]; | ||||||
| 		SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | 
 | ||||||
|  | 		SAXParserFactory saxParserFactory = this.schemaParserFactory; | ||||||
|  | 		if (saxParserFactory == null) { | ||||||
|  | 			saxParserFactory = SAXParserFactory.newInstance(); | ||||||
| 			saxParserFactory.setNamespaceAware(true); | 			saxParserFactory.setNamespaceAware(true); | ||||||
| 			saxParserFactory.setFeature("http://xml.org/sax/features/namespace-prefixes", true); | 			saxParserFactory.setFeature("http://xml.org/sax/features/namespace-prefixes", true); | ||||||
|  | 			this.schemaParserFactory = saxParserFactory; | ||||||
|  | 		} | ||||||
| 		SAXParser saxParser = saxParserFactory.newSAXParser(); | 		SAXParser saxParser = saxParserFactory.newSAXParser(); | ||||||
| 		XMLReader xmlReader = saxParser.getXMLReader(); | 		XMLReader xmlReader = saxParser.getXMLReader(); | ||||||
|  | 
 | ||||||
| 		for (int i = 0; i < resources.length; i++) { | 		for (int i = 0; i < resources.length; i++) { | ||||||
| 			Resource resource = resources[i]; | 			Resource resource = resources[i]; | ||||||
| 			Assert.isTrue(resource != null && resource.exists(), () -> "Resource does not exist: " + resource); | 			Assert.isTrue(resource != null && resource.exists(), () -> "Resource does not exist: " + resource); | ||||||
| 			InputSource inputSource = SaxResourceUtils.createInputSource(resource); | 			InputSource inputSource = SaxResourceUtils.createInputSource(resource); | ||||||
| 			schemaSources[i] = new SAXSource(xmlReader, inputSource); | 			schemaSources[i] = new SAXSource(xmlReader, inputSource); | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
| 		SchemaFactory schemaFactory = SchemaFactory.newInstance(schemaLanguage); | 		SchemaFactory schemaFactory = SchemaFactory.newInstance(schemaLanguage); | ||||||
| 		if (this.schemaResourceResolver != null) { | 		if (this.schemaResourceResolver != null) { | ||||||
| 			schemaFactory.setResourceResolver(this.schemaResourceResolver); | 			schemaFactory.setResourceResolver(this.schemaResourceResolver); | ||||||
|  | @ -886,11 +908,16 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi | ||||||
| 
 | 
 | ||||||
| 		try { | 		try { | ||||||
| 			if (xmlReader == null) { | 			if (xmlReader == null) { | ||||||
| 				SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | 				SAXParserFactory saxParserFactory = this.sourceParserFactory; | ||||||
|  | 				if (saxParserFactory == null) { | ||||||
|  | 					saxParserFactory = SAXParserFactory.newInstance(); | ||||||
| 					saxParserFactory.setNamespaceAware(true); | 					saxParserFactory.setNamespaceAware(true); | ||||||
| 				saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); | 					saxParserFactory.setFeature( | ||||||
| 				String name = "http://xml.org/sax/features/external-general-entities"; | 							"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); | ||||||
| 				saxParserFactory.setFeature(name, isProcessExternalEntities()); | 					saxParserFactory.setFeature( | ||||||
|  | 							"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); | ||||||
|  | 					this.sourceParserFactory = saxParserFactory; | ||||||
|  | 				} | ||||||
| 				SAXParser saxParser = saxParserFactory.newSAXParser(); | 				SAXParser saxParser = saxParserFactory.newSAXParser(); | ||||||
| 				xmlReader = saxParser.getXMLReader(); | 				xmlReader = saxParser.getXMLReader(); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2023 the original author or authors. |  * Copyright 2002-2024 the original author or authors. | ||||||
|  * |  * | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with the License. |  * you may not use this file except in compliance with the License. | ||||||
|  | @ -83,9 +83,10 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { | ||||||
| 	private boolean processExternalEntities = false; | 	private boolean processExternalEntities = false; | ||||||
| 
 | 
 | ||||||
| 	@Nullable | 	@Nullable | ||||||
| 	private DocumentBuilderFactory documentBuilderFactory; | 	private volatile DocumentBuilderFactory documentBuilderFactory; | ||||||
| 
 | 
 | ||||||
| 	private final Object documentBuilderFactoryMonitor = new Object(); | 	@Nullable | ||||||
|  | 	private volatile SAXParserFactory saxParserFactory; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -94,6 +95,8 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setSupportDtd(boolean supportDtd) { | 	public void setSupportDtd(boolean supportDtd) { | ||||||
| 		this.supportDtd = supportDtd; | 		this.supportDtd = supportDtd; | ||||||
|  | 		this.documentBuilderFactory = null; | ||||||
|  | 		this.saxParserFactory = null; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -118,6 +121,8 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { | ||||||
| 		if (processExternalEntities) { | 		if (processExternalEntities) { | ||||||
| 			this.supportDtd = true; | 			this.supportDtd = true; | ||||||
| 		} | 		} | ||||||
|  | 		this.documentBuilderFactory = null; | ||||||
|  | 		this.saxParserFactory = null; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -137,14 +142,13 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { | ||||||
| 	 */ | 	 */ | ||||||
| 	protected Document buildDocument() { | 	protected Document buildDocument() { | ||||||
| 		try { | 		try { | ||||||
| 			DocumentBuilder documentBuilder; | 			DocumentBuilderFactory builderFactory = this.documentBuilderFactory; | ||||||
| 			synchronized (this.documentBuilderFactoryMonitor) { | 			if (builderFactory == null) { | ||||||
| 				if (this.documentBuilderFactory == null) { | 				builderFactory = createDocumentBuilderFactory(); | ||||||
| 					this.documentBuilderFactory = createDocumentBuilderFactory(); | 				this.documentBuilderFactory = builderFactory; | ||||||
| 			} | 			} | ||||||
| 				documentBuilder = createDocumentBuilder(this.documentBuilderFactory); | 			DocumentBuilder builder = createDocumentBuilder(builderFactory); | ||||||
| 			} | 			return builder.newDocument(); | ||||||
| 			return documentBuilder.newDocument(); |  | ||||||
| 		} | 		} | ||||||
| 		catch (ParserConfigurationException ex) { | 		catch (ParserConfigurationException ex) { | ||||||
| 			throw new UnmarshallingFailureException("Could not create document placeholder: " + ex.getMessage(), ex); | 			throw new UnmarshallingFailureException("Could not create document placeholder: " + ex.getMessage(), ex); | ||||||
|  | @ -179,11 +183,11 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { | ||||||
| 	protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory) | 	protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory) | ||||||
| 			throws ParserConfigurationException { | 			throws ParserConfigurationException { | ||||||
| 
 | 
 | ||||||
| 		DocumentBuilder documentBuilder = factory.newDocumentBuilder(); | 		DocumentBuilder builder = factory.newDocumentBuilder(); | ||||||
| 		if (!isProcessExternalEntities()) { | 		if (!isProcessExternalEntities()) { | ||||||
| 			documentBuilder.setEntityResolver(NO_OP_ENTITY_RESOLVER); | 			builder.setEntityResolver(NO_OP_ENTITY_RESOLVER); | ||||||
| 		} | 		} | ||||||
| 		return documentBuilder; | 		return builder; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -193,11 +197,17 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { | ||||||
| 	 * @throws ParserConfigurationException if thrown by JAXP methods | 	 * @throws ParserConfigurationException if thrown by JAXP methods | ||||||
| 	 */ | 	 */ | ||||||
| 	protected XMLReader createXmlReader() throws SAXException, ParserConfigurationException { | 	protected XMLReader createXmlReader() throws SAXException, ParserConfigurationException { | ||||||
| 		SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | 		SAXParserFactory parserFactory = this.saxParserFactory; | ||||||
| 		saxParserFactory.setNamespaceAware(true); | 		if (parserFactory == null) { | ||||||
| 		saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); | 			parserFactory = SAXParserFactory.newInstance(); | ||||||
| 		saxParserFactory.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); | 			parserFactory.setNamespaceAware(true); | ||||||
| 		SAXParser saxParser = saxParserFactory.newSAXParser(); | 			parserFactory.setFeature( | ||||||
|  | 					"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); | ||||||
|  | 			parserFactory.setFeature( | ||||||
|  | 					"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); | ||||||
|  | 			this.saxParserFactory = parserFactory; | ||||||
|  | 		} | ||||||
|  | 		SAXParser saxParser = parserFactory.newSAXParser(); | ||||||
| 		XMLReader xmlReader = saxParser.getXMLReader(); | 		XMLReader xmlReader = saxParser.getXMLReader(); | ||||||
| 		if (!isProcessExternalEntities()) { | 		if (!isProcessExternalEntities()) { | ||||||
| 			xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER); | 			xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER); | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /* | /* | ||||||
|  * Copyright 2002-2023 the original author or authors. |  * Copyright 2002-2024 the original author or authors. | ||||||
|  * |  * | ||||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  * you may not use this file except in compliance with the License. |  * you may not use this file except in compliance with the License. | ||||||
|  | @ -61,6 +61,7 @@ import org.springframework.util.ClassUtils; | ||||||
|  * @author Arjen Poutsma |  * @author Arjen Poutsma | ||||||
|  * @author Sebastien Deleuze |  * @author Sebastien Deleuze | ||||||
|  * @author Rossen Stoyanchev |  * @author Rossen Stoyanchev | ||||||
|  |  * @author Juergen Hoeller | ||||||
|  * @since 3.0 |  * @since 3.0 | ||||||
|  * @see MarshallingHttpMessageConverter |  * @see MarshallingHttpMessageConverter | ||||||
|  */ |  */ | ||||||
|  | @ -70,6 +71,9 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa | ||||||
| 
 | 
 | ||||||
| 	private boolean processExternalEntities = false; | 	private boolean processExternalEntities = false; | ||||||
| 
 | 
 | ||||||
|  | 	@Nullable | ||||||
|  | 	private volatile SAXParserFactory sourceParserFactory; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Indicate whether DTD parsing should be supported. | 	 * Indicate whether DTD parsing should be supported. | ||||||
|  | @ -77,6 +81,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setSupportDtd(boolean supportDtd) { | 	public void setSupportDtd(boolean supportDtd) { | ||||||
| 		this.supportDtd = supportDtd; | 		this.supportDtd = supportDtd; | ||||||
|  | 		this.sourceParserFactory = null; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -97,6 +102,7 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa | ||||||
| 		if (processExternalEntities) { | 		if (processExternalEntities) { | ||||||
| 			this.supportDtd = true; | 			this.supportDtd = true; | ||||||
| 		} | 		} | ||||||
|  | 		this.sourceParserFactory = null; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -156,11 +162,16 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa | ||||||
| 		if (source instanceof StreamSource streamSource) { | 		if (source instanceof StreamSource streamSource) { | ||||||
| 			InputSource inputSource = new InputSource(streamSource.getInputStream()); | 			InputSource inputSource = new InputSource(streamSource.getInputStream()); | ||||||
| 			try { | 			try { | ||||||
| 				SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | 				SAXParserFactory saxParserFactory = this.sourceParserFactory; | ||||||
|  | 				if (saxParserFactory == null) { | ||||||
|  | 					saxParserFactory = SAXParserFactory.newInstance(); | ||||||
| 					saxParserFactory.setNamespaceAware(true); | 					saxParserFactory.setNamespaceAware(true); | ||||||
| 				saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); | 					saxParserFactory.setFeature( | ||||||
| 				String featureName = "http://xml.org/sax/features/external-general-entities"; | 							"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); | ||||||
| 				saxParserFactory.setFeature(featureName, isProcessExternalEntities()); | 					saxParserFactory.setFeature( | ||||||
|  | 							"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); | ||||||
|  | 					this.sourceParserFactory = saxParserFactory; | ||||||
|  | 				} | ||||||
| 				SAXParser saxParser = saxParserFactory.newSAXParser(); | 				SAXParser saxParser = saxParserFactory.newSAXParser(); | ||||||
| 				XMLReader xmlReader = saxParser.getXMLReader(); | 				XMLReader xmlReader = saxParser.getXMLReader(); | ||||||
| 				if (!isProcessExternalEntities()) { | 				if (!isProcessExternalEntities()) { | ||||||
|  |  | ||||||
|  | @ -63,6 +63,7 @@ import org.springframework.util.StreamUtils; | ||||||
|  * |  * | ||||||
|  * @author Arjen Poutsma |  * @author Arjen Poutsma | ||||||
|  * @author Rossen Stoyanchev |  * @author Rossen Stoyanchev | ||||||
|  |  * @author Juergen Hoeller | ||||||
|  * @since 3.0 |  * @since 3.0 | ||||||
|  * @param <T> the converted object type |  * @param <T> the converted object type | ||||||
|  */ |  */ | ||||||
|  | @ -75,11 +76,7 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe | ||||||
| 			(publicID, systemID, base, ns) -> InputStream.nullInputStream(); | 			(publicID, systemID, base, ns) -> InputStream.nullInputStream(); | ||||||
| 
 | 
 | ||||||
| 	private static final Set<Class<?>> SUPPORTED_CLASSES = Set.of( | 	private static final Set<Class<?>> SUPPORTED_CLASSES = Set.of( | ||||||
| 			DOMSource.class, | 			DOMSource.class, SAXSource.class, StAXSource.class, StreamSource.class, Source.class); | ||||||
| 			SAXSource.class, |  | ||||||
| 			StAXSource.class, |  | ||||||
| 			StreamSource.class, |  | ||||||
| 			Source.class); |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	private final TransformerFactory transformerFactory = TransformerFactory.newInstance(); | 	private final TransformerFactory transformerFactory = TransformerFactory.newInstance(); | ||||||
|  | @ -88,6 +85,15 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe | ||||||
| 
 | 
 | ||||||
| 	private boolean processExternalEntities = false; | 	private boolean processExternalEntities = false; | ||||||
| 
 | 
 | ||||||
|  | 	@Nullable | ||||||
|  | 	private volatile DocumentBuilderFactory documentBuilderFactory; | ||||||
|  | 
 | ||||||
|  | 	@Nullable | ||||||
|  | 	private volatile SAXParserFactory saxParserFactory; | ||||||
|  | 
 | ||||||
|  | 	@Nullable | ||||||
|  | 	private volatile XMLInputFactory xmlInputFactory; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Sets the {@link #setSupportedMediaTypes(java.util.List) supportedMediaTypes} | 	 * Sets the {@link #setSupportedMediaTypes(java.util.List) supportedMediaTypes} | ||||||
|  | @ -104,6 +110,9 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe | ||||||
| 	 */ | 	 */ | ||||||
| 	public void setSupportDtd(boolean supportDtd) { | 	public void setSupportDtd(boolean supportDtd) { | ||||||
| 		this.supportDtd = supportDtd; | 		this.supportDtd = supportDtd; | ||||||
|  | 		this.documentBuilderFactory = null; | ||||||
|  | 		this.saxParserFactory = null; | ||||||
|  | 		this.xmlInputFactory = null; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -124,6 +133,9 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe | ||||||
| 		if (processExternalEntities) { | 		if (processExternalEntities) { | ||||||
| 			this.supportDtd = true; | 			this.supportDtd = true; | ||||||
| 		} | 		} | ||||||
|  | 		this.documentBuilderFactory = null; | ||||||
|  | 		this.saxParserFactory = null; | ||||||
|  | 		this.xmlInputFactory = null; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
|  | @ -165,17 +177,21 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe | ||||||
| 
 | 
 | ||||||
| 	private DOMSource readDOMSource(InputStream body, HttpInputMessage inputMessage) throws IOException { | 	private DOMSource readDOMSource(InputStream body, HttpInputMessage inputMessage) throws IOException { | ||||||
| 		try { | 		try { | ||||||
| 			DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); | 			DocumentBuilderFactory builderFactory = this.documentBuilderFactory; | ||||||
| 			documentBuilderFactory.setNamespaceAware(true); | 			if (builderFactory == null) { | ||||||
| 			documentBuilderFactory.setFeature( | 				builderFactory = DocumentBuilderFactory.newInstance(); | ||||||
|  | 				builderFactory.setNamespaceAware(true); | ||||||
|  | 				builderFactory.setFeature( | ||||||
| 						"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); | 						"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); | ||||||
| 			documentBuilderFactory.setFeature( | 				builderFactory.setFeature( | ||||||
| 						"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); | 						"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); | ||||||
| 			DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder(); | 				this.documentBuilderFactory = builderFactory; | ||||||
| 			if (!isProcessExternalEntities()) { |  | ||||||
| 				documentBuilder.setEntityResolver(NO_OP_ENTITY_RESOLVER); |  | ||||||
| 			} | 			} | ||||||
| 			Document document = documentBuilder.parse(body); | 			DocumentBuilder builder = builderFactory.newDocumentBuilder(); | ||||||
|  | 			if (!isProcessExternalEntities()) { | ||||||
|  | 				builder.setEntityResolver(NO_OP_ENTITY_RESOLVER); | ||||||
|  | 			} | ||||||
|  | 			Document document = builder.parse(body); | ||||||
| 			return new DOMSource(document); | 			return new DOMSource(document); | ||||||
| 		} | 		} | ||||||
| 		catch (NullPointerException ex) { | 		catch (NullPointerException ex) { | ||||||
|  | @ -197,11 +213,17 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe | ||||||
| 
 | 
 | ||||||
| 	private SAXSource readSAXSource(InputStream body, HttpInputMessage inputMessage) throws IOException { | 	private SAXSource readSAXSource(InputStream body, HttpInputMessage inputMessage) throws IOException { | ||||||
| 		try { | 		try { | ||||||
| 			SAXParserFactory saxParserFactory = SAXParserFactory.newInstance(); | 			SAXParserFactory parserFactory = this.saxParserFactory; | ||||||
| 			saxParserFactory.setNamespaceAware(true); | 			if (parserFactory == null) { | ||||||
| 			saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); | 				parserFactory = SAXParserFactory.newInstance(); | ||||||
| 			saxParserFactory.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); | 				parserFactory.setNamespaceAware(true); | ||||||
| 			SAXParser saxParser = saxParserFactory.newSAXParser(); | 				parserFactory.setFeature( | ||||||
|  | 						"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); | ||||||
|  | 				parserFactory.setFeature( | ||||||
|  | 						"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities()); | ||||||
|  | 				this.saxParserFactory = parserFactory; | ||||||
|  | 			} | ||||||
|  | 			SAXParser saxParser = parserFactory.newSAXParser(); | ||||||
| 			XMLReader xmlReader = saxParser.getXMLReader(); | 			XMLReader xmlReader = saxParser.getXMLReader(); | ||||||
| 			if (!isProcessExternalEntities()) { | 			if (!isProcessExternalEntities()) { | ||||||
| 				xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER); | 				xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER); | ||||||
|  | @ -217,12 +239,16 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe | ||||||
| 
 | 
 | ||||||
| 	private Source readStAXSource(InputStream body, HttpInputMessage inputMessage) { | 	private Source readStAXSource(InputStream body, HttpInputMessage inputMessage) { | ||||||
| 		try { | 		try { | ||||||
| 			XMLInputFactory inputFactory = XMLInputFactory.newInstance(); | 			XMLInputFactory inputFactory = this.xmlInputFactory; | ||||||
|  | 			if (inputFactory == null) { | ||||||
|  | 				inputFactory = XMLInputFactory.newInstance(); | ||||||
| 				inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, isSupportDtd()); | 				inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, isSupportDtd()); | ||||||
| 				inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, isProcessExternalEntities()); | 				inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, isProcessExternalEntities()); | ||||||
| 				if (!isProcessExternalEntities()) { | 				if (!isProcessExternalEntities()) { | ||||||
| 					inputFactory.setXMLResolver(NO_OP_XML_RESOLVER); | 					inputFactory.setXMLResolver(NO_OP_XML_RESOLVER); | ||||||
| 				} | 				} | ||||||
|  | 				this.xmlInputFactory = inputFactory; | ||||||
|  | 			} | ||||||
| 			XMLStreamReader streamReader = inputFactory.createXMLStreamReader(body); | 			XMLStreamReader streamReader = inputFactory.createXMLStreamReader(body); | ||||||
| 			return new StAXSource(streamReader); | 			return new StAXSource(streamReader); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue