http://jira.mfd.msk:8088/browse/BKI-3191 fix concurrency bug in XmlProcessorStaxImpl

This commit is contained in:
Mikhail Trofimov 2025-09-04 12:48:59 +03:00
parent 3fe63a93ec
commit 111d8b876b
5 changed files with 29 additions and 20 deletions

View file

@ -14,6 +14,7 @@ import ru.nbch.credit_tracker.service.xml.stax.*;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
@Configuration @Configuration
public class XmlConfig { public class XmlConfig {
@ -30,11 +31,11 @@ public class XmlConfig {
@Bean @Bean
public StaxXmlProcessor staxXmlProcessor() { public StaxXmlProcessor staxXmlProcessor() {
List<StaxReader<?>> staxReader = new ArrayList<>(); List<Supplier<StaxReader<?>>> staxReader = new ArrayList<>();
staxReader.add(new SgnlReportStatusStaxReader()); staxReader.add(SgnlReportStatusStaxReader::new);
staxReader.add(new MonitoringRequestStaxReader()); staxReader.add(MonitoringRequestStaxReader::new);
staxReader.add(new OnlineDownloadReportPersonsStaxReader()); staxReader.add(OnlineDownloadReportPersonsStaxReader::new);
staxReader.add(new MonitoringSignalResponseStaxXmlReader()); staxReader.add(MonitoringSignalResponseStaxXmlReader::new);
return new XmlProcessorStaxImpl(staxReader); return new XmlProcessorStaxImpl(staxReader);
} }
} }

View file

@ -1,6 +1,5 @@
package ru.nbch.credit_tracker.service.xml.stax; package ru.nbch.credit_tracker.service.xml.stax;
import org.springframework.stereotype.Component;
import ru.nbch.credit_tracker.entities.external_response.errors.Error; import ru.nbch.credit_tracker.entities.external_response.errors.Error;
import ru.nbch.credit_tracker.entities.external_response.errors.InputParams; import ru.nbch.credit_tracker.entities.external_response.errors.InputParams;
import ru.nbch.credit_tracker.entities.external_response.errors.SgnlReport; import ru.nbch.credit_tracker.entities.external_response.errors.SgnlReport;
@ -8,7 +7,6 @@ import ru.nbch.credit_tracker.entities.external_response.errors.SgnlReport;
import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamReader;
@Component
public class SgnlReportStatusStaxReader extends BaseStaxReader<SgnlReport> { public class SgnlReportStatusStaxReader extends BaseStaxReader<SgnlReport> {
@Override @Override

View file

@ -17,13 +17,14 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier;
public class XmlProcessorStaxImpl implements StaxXmlProcessor { public class XmlProcessorStaxImpl implements StaxXmlProcessor {
private final Logger log = LoggerFactory.getLogger(getClass()); private final Logger log = LoggerFactory.getLogger(getClass());
protected XMLInputFactory xmlInputFactory; protected XMLInputFactory xmlInputFactory;
protected Map<Class<?>, StaxReader<?>> staxReaders = new HashMap<>(); protected Map<Class<?>, Supplier<StaxReader<?>>> staxReaders = new HashMap<>();
public XmlProcessorStaxImpl(List<StaxReader<?>> staxReaders) { public XmlProcessorStaxImpl(List<Supplier<StaxReader<?>>> staxReaders) {
this.xmlInputFactory = XMLInputFactory.newInstance(); this.xmlInputFactory = XMLInputFactory.newInstance();
this.xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false); // полностью выключить DOCTYPE Declaration this.xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false); // полностью выключить DOCTYPE Declaration
// или выключить особо опасные возможности (менее строгое ограничение XXE, но достаточное): // или выключить особо опасные возможности (менее строгое ограничение XXE, но достаточное):
@ -32,10 +33,13 @@ public class XmlProcessorStaxImpl implements StaxXmlProcessor {
this.xmlInputFactory.setXMLResolver((publicID, systemID, baseURI, namespace) -> { this.xmlInputFactory.setXMLResolver((publicID, systemID, baseURI, namespace) -> {
throw new XMLStreamException("External entities are disabled"); throw new XMLStreamException("External entities are disabled");
}); });
staxReaders.forEach(reader -> this.staxReaders.put(reader.type(), reader)); staxReaders.forEach(supplier -> {
Class<?> type = supplier.get().type();
this.staxReaders.put(type, supplier);
});
} }
public XmlProcessorStaxImpl(StaxReader<?>... staxReaders) { public XmlProcessorStaxImpl(Supplier<StaxReader<?>>... staxReaders) {
this(Arrays.asList(staxReaders)); this(Arrays.asList(staxReaders));
} }
@ -43,8 +47,9 @@ public class XmlProcessorStaxImpl implements StaxXmlProcessor {
public <Z> Z read(String xml, Class<Z> clazz) { public <Z> Z read(String xml, Class<Z> clazz) {
try { try {
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new StringReader(xml)); XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new StringReader(xml));
Supplier<StaxReader<?>> staxReaderSupplier = staxReaders.get(clazz);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
StaxReader<Z> staxProcessor = (StaxReader<Z>) staxReaders.get(clazz); StaxReader<Z> staxProcessor = (StaxReader<Z>) staxReaderSupplier.get();
if (staxProcessor != null) { if (staxProcessor != null) {
return staxProcessor.read(xmlStreamReader); return staxProcessor.read(xmlStreamReader);
} }
@ -62,8 +67,9 @@ public class XmlProcessorStaxImpl implements StaxXmlProcessor {
public <Z> Z read(byte[] xml, Class<Z> clazz) { public <Z> Z read(byte[] xml, Class<Z> clazz) {
try { try {
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(xml)); XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(new ByteArrayInputStream(xml));
Supplier<StaxReader<?>> staxReaderSupplier = staxReaders.get(clazz);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
StaxReader<Z> staxProcessor = (StaxReader<Z>) staxReaders.get(clazz); StaxReader<Z> staxProcessor = (StaxReader<Z>) staxReaderSupplier.get();
if (staxProcessor != null) { if (staxProcessor != null) {
return staxProcessor.read(xmlStreamReader); return staxProcessor.read(xmlStreamReader);
} }
@ -81,8 +87,9 @@ public class XmlProcessorStaxImpl implements StaxXmlProcessor {
public <Z> Z read(InputStream inputStream, Class<Z> clazz) { public <Z> Z read(InputStream inputStream, Class<Z> clazz) {
try { try {
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(inputStream); XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(inputStream);
Supplier<StaxReader<?>> staxReaderSupplier = staxReaders.get(clazz);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
StaxReader<Z> staxProcessor = (StaxReader<Z>) staxReaders.get(clazz); StaxReader<Z> staxProcessor = (StaxReader<Z>) staxReaderSupplier.get();
if (staxProcessor != null) { if (staxProcessor != null) {
return staxProcessor.read(xmlStreamReader); return staxProcessor.read(xmlStreamReader);
} }
@ -100,8 +107,9 @@ public class XmlProcessorStaxImpl implements StaxXmlProcessor {
public <Z> Z read(InputStream inputStream, Class<Z> clazz, Consumer<Z> objProcessor, Function<Z, Boolean> emptyBatchCheckFunction, Integer batchSize, String endBatchElementPath) { public <Z> Z read(InputStream inputStream, Class<Z> clazz, Consumer<Z> objProcessor, Function<Z, Boolean> emptyBatchCheckFunction, Integer batchSize, String endBatchElementPath) {
try { try {
XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(inputStream); XMLStreamReader xmlStreamReader = xmlInputFactory.createXMLStreamReader(inputStream);
Supplier<StaxReader<?>> staxReaderSupplier = staxReaders.get(clazz);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
StaxReader<Z> staxProcessor = (StaxReader<Z>) staxReaders.get(clazz); StaxReader<Z> staxProcessor = (StaxReader<Z>) staxReaderSupplier.get();
if (staxProcessor != null) { if (staxProcessor != null) {
return staxProcessor.read(xmlStreamReader, objProcessor, emptyBatchCheckFunction, batchSize, endBatchElementPath); return staxProcessor.read(xmlStreamReader, objProcessor, emptyBatchCheckFunction, batchSize, endBatchElementPath);
} }

View file

@ -16,6 +16,7 @@ import javax.xml.stream.XMLStreamException;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
@SpringBootTest(classes = {StaxTest.TestConfig.class}) @SpringBootTest(classes = {StaxTest.TestConfig.class})
public class StaxTest { public class StaxTest {
@ -31,9 +32,9 @@ public class StaxTest {
public static class TestConfig { public static class TestConfig {
@Bean @Bean
public StaxXmlProcessor xmlProcessor() { public StaxXmlProcessor xmlProcessor() {
List<StaxReader<?>> staxReader = new ArrayList<>(); List<Supplier<StaxReader<?>>> staxReader = new ArrayList<>();
staxReader.add(new MonitoringRequestStaxReader()); staxReader.add(MonitoringRequestStaxReader::new);
staxReader.add(new OnlineDownloadReportPersonsStaxReader()); staxReader.add(OnlineDownloadReportPersonsStaxReader::new);
return new XmlProcessorStaxImpl(staxReader); return new XmlProcessorStaxImpl(staxReader);
} }
} }

View file

@ -22,6 +22,7 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Stream; import java.util.stream.Stream;
import java.util.zip.ZipInputStream; import java.util.zip.ZipInputStream;
@ -41,8 +42,8 @@ public class ValidationUtilTest {
public static class TestConfig { public static class TestConfig {
@Bean @Bean
public StaxXmlProcessor xmlProcessor() { public StaxXmlProcessor xmlProcessor() {
List<StaxReader<?>> staxReader = new ArrayList<>(); List<Supplier<StaxReader<?>>> staxReader = new ArrayList<>();
staxReader.add(new MonitoringRequestStaxReader()); staxReader.add(MonitoringRequestStaxReader::new);
return new XmlProcessorStaxImpl(staxReader); return new XmlProcessorStaxImpl(staxReader);
} }
} }