mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-10-03 13:39:34 +00:00
Merge branch '7.0.x'
This commit is contained in:
@@ -102,7 +102,7 @@ public final class ConcurrentLruCache<K, V> {
|
||||
if (this.capacity == 0) {
|
||||
return this.generator.apply(key);
|
||||
}
|
||||
final Node<K, V> node = this.cache.get(key);
|
||||
Node<K, V> node = this.cache.get(key);
|
||||
if (node == null) {
|
||||
V value = this.generator.apply(key);
|
||||
put(key, value);
|
||||
@@ -115,9 +115,9 @@ public final class ConcurrentLruCache<K, V> {
|
||||
private void put(K key, V value) {
|
||||
Assert.notNull(key, "key must not be null");
|
||||
Assert.notNull(value, "value must not be null");
|
||||
final CacheEntry<V> cacheEntry = new CacheEntry<>(value, CacheEntryState.ACTIVE);
|
||||
final Node<K, V> node = new Node<>(key, cacheEntry);
|
||||
final Node<K, V> prior = this.cache.putIfAbsent(node.key, node);
|
||||
CacheEntry<V> cacheEntry = new CacheEntry<>(value, CacheEntryState.ACTIVE);
|
||||
Node<K, V> node = new Node<>(key, cacheEntry);
|
||||
Node<K, V> prior = this.cache.putIfAbsent(node.key, node);
|
||||
if (prior == null) {
|
||||
processWrite(new AddTask(node));
|
||||
}
|
||||
@@ -128,7 +128,7 @@ public final class ConcurrentLruCache<K, V> {
|
||||
|
||||
private void processRead(Node<K, V> node) {
|
||||
boolean drainRequested = this.readOperations.recordRead(node);
|
||||
final DrainStatus status = this.drainStatus.get();
|
||||
DrainStatus status = this.drainStatus.get();
|
||||
if (status.shouldDrainBuffers(drainRequested)) {
|
||||
drainOperations();
|
||||
}
|
||||
@@ -228,7 +228,7 @@ public final class ConcurrentLruCache<K, V> {
|
||||
* {@code false} if there was no matching key
|
||||
*/
|
||||
public boolean remove(K key) {
|
||||
final Node<K, V> node = this.cache.remove(key);
|
||||
Node<K, V> node = this.cache.remove(key);
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -237,27 +237,29 @@ public final class ConcurrentLruCache<K, V> {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* Transition the node from the {@code active} state to the {@code pending removal} state,
|
||||
* if the transition is valid.
|
||||
*/
|
||||
private void markForRemoval(Node<K, V> node) {
|
||||
for (; ; ) {
|
||||
final CacheEntry<V> current = node.get();
|
||||
while (true) {
|
||||
CacheEntry<V> current = node.get();
|
||||
if (!current.isActive()) {
|
||||
return;
|
||||
}
|
||||
final CacheEntry<V> pendingRemoval = new CacheEntry<>(current.value, CacheEntryState.PENDING_REMOVAL);
|
||||
CacheEntry<V> pendingRemoval = new CacheEntry<>(current.value, CacheEntryState.PENDING_REMOVAL);
|
||||
if (node.compareAndSet(current, pendingRemoval)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write operation recorded when a new entry is added to the cache.
|
||||
*/
|
||||
private final class AddTask implements Runnable {
|
||||
|
||||
final Node<K, V> node;
|
||||
|
||||
AddTask(Node<K, V> node) {
|
||||
@@ -275,7 +277,7 @@ public final class ConcurrentLruCache<K, V> {
|
||||
|
||||
private void evictEntries() {
|
||||
while (currentSize.get() > capacity) {
|
||||
final Node<K, V> node = evictionQueue.poll();
|
||||
Node<K, V> node = evictionQueue.poll();
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
@@ -283,7 +285,6 @@ public final class ConcurrentLruCache<K, V> {
|
||||
markAsRemoved(node);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -291,6 +292,7 @@ public final class ConcurrentLruCache<K, V> {
|
||||
* Write operation recorded when an entry is removed to the cache.
|
||||
*/
|
||||
private final class RemovalTask implements Runnable {
|
||||
|
||||
final Node<K, V> node;
|
||||
|
||||
RemovalTask(Node<K, V> node) {
|
||||
@@ -310,7 +312,7 @@ public final class ConcurrentLruCache<K, V> {
|
||||
*/
|
||||
private enum DrainStatus {
|
||||
|
||||
/*
|
||||
/**
|
||||
* No drain operation currently running.
|
||||
*/
|
||||
IDLE {
|
||||
@@ -320,7 +322,7 @@ public final class ConcurrentLruCache<K, V> {
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
/**
|
||||
* A drain operation is required due to a pending write modification.
|
||||
*/
|
||||
REQUIRED {
|
||||
@@ -330,7 +332,7 @@ public final class ConcurrentLruCache<K, V> {
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
/**
|
||||
* A drain operation is in progress.
|
||||
*/
|
||||
PROCESSING {
|
||||
@@ -367,12 +369,6 @@ public final class ConcurrentLruCache<K, V> {
|
||||
|
||||
private static final int BUFFER_COUNT = detectNumberOfBuffers();
|
||||
|
||||
private static int detectNumberOfBuffers() {
|
||||
int availableProcessors = Runtime.getRuntime().availableProcessors();
|
||||
int nextPowerOfTwo = 1 << (Integer.SIZE - Integer.numberOfLeadingZeros(availableProcessors - 1));
|
||||
return Math.min(4, nextPowerOfTwo);
|
||||
}
|
||||
|
||||
private static final int BUFFERS_MASK = BUFFER_COUNT - 1;
|
||||
|
||||
private static final int MAX_PENDING_OPERATIONS = 32;
|
||||
@@ -383,19 +379,13 @@ public final class ConcurrentLruCache<K, V> {
|
||||
|
||||
private static final int BUFFER_INDEX_MASK = BUFFER_SIZE - 1;
|
||||
|
||||
/*
|
||||
* Number of operations recorded, for each buffer
|
||||
*/
|
||||
// Number of operations recorded, for each buffer
|
||||
private final AtomicLongArray recordedCount = new AtomicLongArray(BUFFER_COUNT);
|
||||
|
||||
/*
|
||||
* Number of operations read, for each buffer
|
||||
*/
|
||||
// Number of operations read, for each buffer
|
||||
private final long[] readCount = new long[BUFFER_COUNT];
|
||||
|
||||
/*
|
||||
* Number of operations processed, for each buffer
|
||||
*/
|
||||
// Number of operations processed, for each buffer
|
||||
private final AtomicLongArray processedCount = new AtomicLongArray(BUFFER_COUNT);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@@ -403,10 +393,11 @@ public final class ConcurrentLruCache<K, V> {
|
||||
|
||||
private final EvictionQueue<K, V> evictionQueue;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
ReadOperations(EvictionQueue<K, V> evictionQueue) {
|
||||
this.evictionQueue = evictionQueue;
|
||||
for (int i = 0; i < BUFFER_COUNT; i++) {
|
||||
this.buffers[i] = new AtomicReferenceArray<>(BUFFER_SIZE);
|
||||
this.buffers[i] = new AtomicReferenceArray(BUFFER_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,6 +449,12 @@ public final class ConcurrentLruCache<K, V> {
|
||||
}
|
||||
this.processedCount.lazySet(bufferIndex, writeCount);
|
||||
}
|
||||
|
||||
private static int detectNumberOfBuffers() {
|
||||
int availableProcessors = Runtime.getRuntime().availableProcessors();
|
||||
int nextPowerOfTwo = 1 << (Integer.SIZE - Integer.numberOfLeadingZeros(availableProcessors - 1));
|
||||
return Math.min(4, nextPowerOfTwo);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -536,10 +533,9 @@ public final class ConcurrentLruCache<K, V> {
|
||||
if (this.first == null) {
|
||||
return null;
|
||||
}
|
||||
final Node<K, V> f = this.first;
|
||||
final Node<K, V> next = f.getNext();
|
||||
Node<K, V> f = this.first;
|
||||
Node<K, V> next = f.getNext();
|
||||
f.setNext(null);
|
||||
|
||||
this.first = next;
|
||||
if (next == null) {
|
||||
this.last = null;
|
||||
@@ -558,13 +554,12 @@ public final class ConcurrentLruCache<K, V> {
|
||||
}
|
||||
|
||||
private boolean contains(Node<K, V> e) {
|
||||
return (e.getPrevious() != null) || (e.getNext() != null) || (e == this.first);
|
||||
return (e.getPrevious() != null || e.getNext() != null || e == this.first);
|
||||
}
|
||||
|
||||
private void linkLast(final Node<K, V> e) {
|
||||
final Node<K, V> l = this.last;
|
||||
private void linkLast(Node<K, V> e) {
|
||||
Node<K, V> l = this.last;
|
||||
this.last = e;
|
||||
|
||||
if (l == null) {
|
||||
this.first = e;
|
||||
}
|
||||
@@ -575,8 +570,8 @@ public final class ConcurrentLruCache<K, V> {
|
||||
}
|
||||
|
||||
private void unlink(Node<K, V> e) {
|
||||
final Node<K, V> prev = e.getPrevious();
|
||||
final Node<K, V> next = e.getNext();
|
||||
Node<K, V> prev = e.getPrevious();
|
||||
Node<K, V> next = e.getNext();
|
||||
if (prev == null) {
|
||||
this.first = next;
|
||||
}
|
||||
|
||||
@@ -892,17 +892,29 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
|
||||
// By default, Spring will prevent the processing of external entities.
|
||||
// This is a mitigation against XXE attacks.
|
||||
if (xmlReader == null) {
|
||||
SAXParserFactory saxParserFactory = this.sourceParserFactory;
|
||||
if (saxParserFactory == null) {
|
||||
saxParserFactory = SAXParserFactory.newInstance();
|
||||
saxParserFactory.setNamespaceAware(true);
|
||||
saxParserFactory.setFeature(
|
||||
"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd());
|
||||
saxParserFactory.setFeature(
|
||||
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
|
||||
this.sourceParserFactory = saxParserFactory;
|
||||
SAXParserFactory factory = this.sourceParserFactory;
|
||||
if (factory == null) {
|
||||
factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
try {
|
||||
factory.setFeature(
|
||||
"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Xerces properties not recognized/supported - ignore
|
||||
}
|
||||
try {
|
||||
factory.setFeature(
|
||||
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
|
||||
factory.setFeature(
|
||||
"http://xml.org/sax/features/external-parameter-entities", isProcessExternalEntities());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// SAX properties not recognized/supported - ignore
|
||||
}
|
||||
this.sourceParserFactory = factory;
|
||||
}
|
||||
SAXParser saxParser = saxParserFactory.newSAXParser();
|
||||
SAXParser saxParser = factory.newSAXParser();
|
||||
xmlReader = saxParser.getXMLReader();
|
||||
}
|
||||
if (!isProcessExternalEntities()) {
|
||||
@@ -910,8 +922,8 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
|
||||
}
|
||||
return new SAXSource(xmlReader, inputSource);
|
||||
}
|
||||
catch (SAXException | ParserConfigurationException ex) {
|
||||
logger.info("Processing of external entities could not be disabled", ex);
|
||||
catch (Exception ex) {
|
||||
logger.warn("Processing of external entities could not be disabled", ex);
|
||||
return source;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
|
||||
private static final EntityResolver NO_OP_ENTITY_RESOLVER =
|
||||
(publicId, systemId) -> new InputSource(new StringReader(""));
|
||||
|
||||
|
||||
/** Logger available to subclasses. */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@@ -165,8 +166,22 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
|
||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setValidating(false);
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd());
|
||||
factory.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
|
||||
try {
|
||||
factory.setFeature(
|
||||
"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Xerces properties not recognized/supported - ignore
|
||||
}
|
||||
try {
|
||||
factory.setFeature(
|
||||
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
|
||||
factory.setFeature(
|
||||
"http://xml.org/sax/features/external-parameter-entities", isProcessExternalEntities());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// SAX properties not recognized/supported - ignore
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
|
||||
@@ -195,17 +210,29 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
|
||||
* @throws ParserConfigurationException if thrown by JAXP methods
|
||||
*/
|
||||
protected XMLReader createXmlReader() throws SAXException, ParserConfigurationException {
|
||||
SAXParserFactory parserFactory = this.saxParserFactory;
|
||||
if (parserFactory == null) {
|
||||
parserFactory = SAXParserFactory.newInstance();
|
||||
parserFactory.setNamespaceAware(true);
|
||||
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;
|
||||
SAXParserFactory factory = this.saxParserFactory;
|
||||
if (factory == null) {
|
||||
factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
try {
|
||||
factory.setFeature(
|
||||
"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Xerces properties not recognized/supported - ignore
|
||||
}
|
||||
try {
|
||||
factory.setFeature(
|
||||
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
|
||||
factory.setFeature(
|
||||
"http://xml.org/sax/features/external-parameter-entities", isProcessExternalEntities());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// SAX properties not recognized/supported - ignore
|
||||
}
|
||||
this.saxParserFactory = factory;
|
||||
}
|
||||
SAXParser saxParser = parserFactory.newSAXParser();
|
||||
SAXParser saxParser = factory.newSAXParser();
|
||||
XMLReader xmlReader = saxParser.getXMLReader();
|
||||
if (!isProcessExternalEntities()) {
|
||||
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
|
||||
@@ -456,8 +483,7 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
|
||||
catch (NullPointerException ex) {
|
||||
if (!isSupportDtd()) {
|
||||
throw new UnmarshallingFailureException("NPE while unmarshalling. " +
|
||||
"This can happen on JDK 1.6 due to the presence of DTD " +
|
||||
"declarations, which are disabled.");
|
||||
"This can happen due to the presence of DTD declarations, which are disabled.");
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
|
||||
+27
-17
@@ -19,7 +19,6 @@ package org.springframework.http.converter.xml;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
import javax.xml.transform.Result;
|
||||
@@ -39,7 +38,6 @@ import jakarta.xml.bind.annotation.XmlType;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.xml.sax.EntityResolver;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.XMLReader;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
@@ -68,6 +66,10 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessageConverter<Object> {
|
||||
|
||||
private static final EntityResolver NO_OP_ENTITY_RESOLVER =
|
||||
(publicId, systemId) -> new InputSource(new StringReader(""));
|
||||
|
||||
|
||||
private boolean supportDtd = false;
|
||||
|
||||
private boolean processExternalEntities = false;
|
||||
@@ -181,24 +183,36 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
|
||||
try {
|
||||
// By default, Spring will prevent the processing of external entities.
|
||||
// This is a mitigation against XXE attacks.
|
||||
SAXParserFactory saxParserFactory = this.sourceParserFactory;
|
||||
if (saxParserFactory == null) {
|
||||
saxParserFactory = SAXParserFactory.newInstance();
|
||||
saxParserFactory.setNamespaceAware(true);
|
||||
saxParserFactory.setFeature(
|
||||
"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd());
|
||||
saxParserFactory.setFeature(
|
||||
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
|
||||
this.sourceParserFactory = saxParserFactory;
|
||||
SAXParserFactory factory = this.sourceParserFactory;
|
||||
if (factory == null) {
|
||||
factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
try {
|
||||
factory.setFeature(
|
||||
"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Xerces properties not recognized/supported - ignore
|
||||
}
|
||||
try {
|
||||
factory.setFeature(
|
||||
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
|
||||
factory.setFeature(
|
||||
"http://xml.org/sax/features/external-parameter-entities", isProcessExternalEntities());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// SAX properties not recognized/supported - ignore
|
||||
}
|
||||
this.sourceParserFactory = factory;
|
||||
}
|
||||
SAXParser saxParser = saxParserFactory.newSAXParser();
|
||||
SAXParser saxParser = factory.newSAXParser();
|
||||
XMLReader xmlReader = saxParser.getXMLReader();
|
||||
if (!isProcessExternalEntities()) {
|
||||
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
|
||||
}
|
||||
return new SAXSource(xmlReader, inputSource);
|
||||
}
|
||||
catch (SAXException | ParserConfigurationException ex) {
|
||||
catch (Exception ex) {
|
||||
logger.warn("Processing of external entities could not be disabled", ex);
|
||||
return source;
|
||||
}
|
||||
@@ -245,8 +259,4 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
private static final EntityResolver NO_OP_ENTITY_RESOLVER =
|
||||
(publicId, systemId) -> new InputSource(new StringReader(""));
|
||||
|
||||
}
|
||||
|
||||
+49
-21
@@ -181,17 +181,29 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
|
||||
try {
|
||||
// By default, Spring will prevent the processing of external entities.
|
||||
// This is a mitigation against XXE attacks.
|
||||
DocumentBuilderFactory builderFactory = this.documentBuilderFactory;
|
||||
if (builderFactory == null) {
|
||||
builderFactory = DocumentBuilderFactory.newInstance();
|
||||
builderFactory.setNamespaceAware(true);
|
||||
builderFactory.setFeature(
|
||||
"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd());
|
||||
builderFactory.setFeature(
|
||||
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
|
||||
this.documentBuilderFactory = builderFactory;
|
||||
DocumentBuilderFactory factory = this.documentBuilderFactory;
|
||||
if (factory == null) {
|
||||
factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
try {
|
||||
factory.setFeature(
|
||||
"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Xerces properties not recognized/supported - ignore
|
||||
}
|
||||
try {
|
||||
factory.setFeature(
|
||||
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
|
||||
factory.setFeature(
|
||||
"http://xml.org/sax/features/external-parameter-entities", isProcessExternalEntities());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// SAX properties not recognized/supported - ignore
|
||||
}
|
||||
this.documentBuilderFactory = factory;
|
||||
}
|
||||
DocumentBuilder builder = builderFactory.newDocumentBuilder();
|
||||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||
if (!isProcessExternalEntities()) {
|
||||
builder.setEntityResolver(NO_OP_ENTITY_RESOLVER);
|
||||
}
|
||||
@@ -217,17 +229,29 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
|
||||
|
||||
private SAXSource readSAXSource(InputStream body, HttpInputMessage inputMessage) throws IOException {
|
||||
try {
|
||||
SAXParserFactory parserFactory = this.saxParserFactory;
|
||||
if (parserFactory == null) {
|
||||
parserFactory = SAXParserFactory.newInstance();
|
||||
parserFactory.setNamespaceAware(true);
|
||||
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;
|
||||
SAXParserFactory factory = this.saxParserFactory;
|
||||
if (factory == null) {
|
||||
factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
try {
|
||||
factory.setFeature(
|
||||
"http://apache.org/xml/features/disallow-doctype-decl", !isSupportDtd());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Xerces properties not recognized/supported - ignore
|
||||
}
|
||||
try {
|
||||
factory.setFeature(
|
||||
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
|
||||
factory.setFeature(
|
||||
"http://xml.org/sax/features/external-parameter-entities", isProcessExternalEntities());
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// SAX properties not recognized/supported - ignore
|
||||
}
|
||||
this.saxParserFactory = factory;
|
||||
}
|
||||
SAXParser saxParser = parserFactory.newSAXParser();
|
||||
SAXParser saxParser = factory.newSAXParser();
|
||||
XMLReader xmlReader = saxParser.getXMLReader();
|
||||
if (!isProcessExternalEntities()) {
|
||||
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
|
||||
@@ -235,7 +259,11 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
|
||||
byte[] bytes = StreamUtils.copyToByteArray(body);
|
||||
return new SAXSource(xmlReader, new InputSource(new ByteArrayInputStream(bytes)));
|
||||
}
|
||||
catch (SAXException | ParserConfigurationException ex) {
|
||||
catch (ParserConfigurationException ex) {
|
||||
throw new HttpMessageNotReadableException(
|
||||
"Could not set feature: " + ex.getMessage(), ex, inputMessage);
|
||||
}
|
||||
catch (SAXException ex) {
|
||||
throw new HttpMessageNotReadableException(
|
||||
"Could not parse document: " + ex.getMessage(), ex, inputMessage);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user