private Source processSource(Source source) {
if (StaxUtils.isStaxSource(source) || source instanceof DOMSource) {
return source;
}
XMLReader xmlReader = null;
InputSource inputSource = null;
if (source instanceof SAXSource saxSource) {
xmlReader = saxSource.getXMLReader();
inputSource = saxSource.getInputSource();
}
else if (source instanceof StreamSource streamSource) {
if (streamSource.getInputStream() != null) {
inputSource = new InputSource(streamSource.getInputStream());
}
else if (streamSource.getReader() != null) {
inputSource = new InputSource(streamSource.getReader());
}
else {
inputSource = new InputSource(streamSource.getSystemId());
}
}
try {
if (xmlReader == null) {
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
saxParserFactory.setNamespaceAware(true);
saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd()); //EXPENSIVE
String name = "http://xml.org/sax/features/external-general-entities";
saxParserFactory.setFeature(name, isProcessExternalEntities()); //EXPENSIVE
SAXParser saxParser = saxParserFactory.newSAXParser();
xmlReader = saxParser.getXMLReader();
}
if (!isProcessExternalEntities()) {
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
}
return new SAXSource(xmlReader, inputSource);
}
catch (SAXException | ParserConfigurationException ex) {
logger.info("Processing of external entities could not be disabled", ex);
return source;
}
}
This is the current code. But creating a new SAXParserverFactory for every processSource is expensive. Calling setFeature can often result in code that then goes off and looks for resource files, which often are not there, until finally picking a default.
See https://docs.oracle.com/javase%2F7%2Fdocs%2Fapi%2F%2F/javax/xml/parsers/SAXParserFactory.html#newInstance()
However, (as stated in supplied link) Once an application has obtained a reference to a SAXParserFactory, it can be used to obtain parser instances.
It seems like the code ought to be: ``` private SAXParserFactory saxParserFactory = null;
private Source processSource(Source source) {
if (StaxUtils.isStaxSource(source) || source instanceof DOMSource) {
return source;
}
XMLReader xmlReader = null;
InputSource inputSource = null;
if (source instanceof SAXSource saxSource) {
xmlReader = saxSource.getXMLReader();
inputSource = saxSource.getInputSource();
}
else if (source instanceof StreamSource streamSource) {
if (streamSource.getInputStream() != null) {
inputSource = new InputSource(streamSource.getInputStream());
}
else if (streamSource.getReader() != null) {
inputSource = new InputSource(streamSource.getReader());
}
else {
inputSource = new InputSource(streamSource.getSystemId());
}
}
try {
if (xmlReader == null) {
if(saxParserFactory == null ) {
saxParserFactory = SAXParserFactory.newInstance();
saxParserFactory.setNamespaceAware(true);
saxParserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd());
String name = "http://xml.org/sax/features/external-general-entities";
saxParserFactory.setFeature(name, isProcessExternalEntities());
}
SAXParser saxParser = saxParserFactory.newSAXParser();
xmlReader = saxParser.getXMLReader();
}
if (!isProcessExternalEntities()) {
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
}
return new SAXSource(xmlReader, inputSource);
}
catch (SAXException | ParserConfigurationException ex) {
logger.info("Processing of external entities could not be disabled", ex);
return source;
}
}
Comment From: sturose
The same pattern should also be applied to Jaxb2RootElementHttpMessageConverter as it is doing the same thing.
Comment From: jhoeller
We have a couple of places where we are creating a SAXParserFactory
on the fly, as a consequence of #27239. We need to revise this to cache the SAXParserFactory
instance in all applicable places.