From c4ad7de6e35ab5e72699b557b258ca1b59f547a7 Mon Sep 17 00:00:00 2001 From: Rob Rudin Date: Mon, 5 Jan 2026 14:05:31 -0500 Subject: [PATCH] MLE-26427 Refactoring JAXP usage Doing this before adding support for XML exclusions in the incremental write feature. Standardizes on a single way of creating a DocumentBuilderFactory. Also made a year-change-based fix in LegalHoldsTest. --- .../marklogic/client/impl/NodeConverter.java | 16 +-- .../marklogic/client/impl/XmlFactories.java | 103 ++++++++++++------ .../com/marklogic/client/io/DOMHandle.java | 65 ++--------- .../client/io/DocumentMetadataHandle.java | 7 +- .../client/test/BufferableHandleTest.java | 17 ++- .../com/marklogic/client/test/Common.java | 6 +- .../client/test/DeleteSearchTest.java | 15 +-- .../com/marklogic/client/test/EvalTest.java | 14 +-- .../test/GeospatialRegionQueriesTest.java | 9 +- .../marklogic/client/test/HandleAsTest.java | 8 +- .../client/test/PlanGeneratedBase.java | 10 +- .../client/test/QueryOptionsManagerTest.java | 15 +-- .../client/test/RawQueryDefinitionTest.java | 9 +- .../client/test/RequestLoggerTest.java | 14 +-- .../client/test/SearchFacetTest.java | 9 +- .../client/test/XMLDocumentTest.java | 13 +-- .../test/datamovement/LegalHoldsTest.java | 4 +- .../test/datamovement/ScenariosTest.java | 10 +- .../test/io/DocumentMetadataHandleTest.java | 9 +- 19 files changed, 144 insertions(+), 209 deletions(-) diff --git a/marklogic-client-api/src/main/java/com/marklogic/client/impl/NodeConverter.java b/marklogic-client-api/src/main/java/com/marklogic/client/impl/NodeConverter.java index a885dc6e8..1baf50ba5 100644 --- a/marklogic-client-api/src/main/java/com/marklogic/client/impl/NodeConverter.java +++ b/marklogic-client-api/src/main/java/com/marklogic/client/impl/NodeConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.impl; @@ -35,7 +35,6 @@ public class NodeConverter { static private ObjectMapper mapper; - static private DocumentBuilderFactory documentBuilderFactory; static private XMLInputFactory xmlInputFactory; private NodeConverter() { @@ -49,16 +48,7 @@ static private ObjectMapper getMapper() { } return mapper; } - static private DocumentBuilderFactory getDocumentBuilderFactory() { - // okay if one thread overwrites another during lazy initialization - if (documentBuilderFactory == null) { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - documentBuilderFactory = factory; - } - return documentBuilderFactory; - } + static private XMLInputFactory getXMLInputFactory() { // okay if one thread overwrites another during lazy initialization if (xmlInputFactory == null) { @@ -265,7 +255,7 @@ static public Stream ReaderToJsonParser(Stream val static public Document InputStreamToDocument(InputStream inputStream) { try { - return (inputStream == null) ? null : getDocumentBuilderFactory().newDocumentBuilder().parse(inputStream); + return (inputStream == null) ? null : XmlFactories.getDocumentBuilderFactory().newDocumentBuilder().parse(inputStream); } catch(SAXException | IOException | ParserConfigurationException e) { throw new RuntimeException(e); } diff --git a/marklogic-client-api/src/main/java/com/marklogic/client/impl/XmlFactories.java b/marklogic-client-api/src/main/java/com/marklogic/client/impl/XmlFactories.java index 6f1484159..6773ef19f 100644 --- a/marklogic-client-api/src/main/java/com/marklogic/client/impl/XmlFactories.java +++ b/marklogic-client-api/src/main/java/com/marklogic/client/impl/XmlFactories.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.impl; @@ -7,24 +7,25 @@ import org.slf4j.LoggerFactory; import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import javax.xml.stream.FactoryConfigurationError; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLOutputFactory; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactory; import java.lang.ref.SoftReference; +import java.util.function.Supplier; public final class XmlFactories { private static final Logger logger = LoggerFactory.getLogger(XmlFactories.class); private static final CachedInstancePerThreadSupplier cachedOutputFactory = - new CachedInstancePerThreadSupplier(new Supplier() { - @Override - public XMLOutputFactory get() { - return makeNewOutputFactory(); - } - }); + new CachedInstancePerThreadSupplier<>(XmlFactories::makeNewOutputFactory); + + private static final CachedInstancePerThreadSupplier cachedDocumentBuilderFactory = + new CachedInstancePerThreadSupplier<>(XmlFactories::makeNewDocumentBuilderFactory); private XmlFactories() {} // preventing instances of utility class @@ -62,21 +63,78 @@ public static TransformerFactory makeNewTransformerFactory() { try { factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); } catch (TransformerConfigurationException e) { - logger.warn("Unable to set {} on TransformerFactory; cause: {}", XMLConstants.FEATURE_SECURE_PROCESSING, e.getMessage()); + logTransformerWarning(XMLConstants.FEATURE_SECURE_PROCESSING, e.getMessage()); } try { factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); } catch (IllegalArgumentException e) { - logger.warn("Unable to set {} on TransformerFactory; cause: {}", XMLConstants.ACCESS_EXTERNAL_DTD, e.getMessage()); + logTransformerWarning(XMLConstants.ACCESS_EXTERNAL_DTD, e.getMessage()); } try { factory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); } catch (IllegalArgumentException e) { - logger.warn("Unable to set {} on TransformerFactory; cause: {}", XMLConstants.ACCESS_EXTERNAL_STYLESHEET, e.getMessage()); + logTransformerWarning(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, e.getMessage()); } return factory; } + private static void logTransformerWarning(String xmlConstant, String errorMessage) { + logger.warn("Unable to set {} on TransformerFactory; cause: {}", xmlConstant, errorMessage); + } + + private static DocumentBuilderFactory makeNewDocumentBuilderFactory() { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + // Default to best practices for conservative security including recommendations per + // https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.md + try { + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + } catch (ParserConfigurationException e) { + logger.warn("Unable to set FEATURE_SECURE_PROCESSING on DocumentBuilderFactory; cause: {}", e.getMessage()); + } + try { + factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + } catch (ParserConfigurationException e) { + logger.warn("Unable to set disallow-doctype-decl on DocumentBuilderFactory; cause: {}", e.getMessage()); + } + try { + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + } catch (ParserConfigurationException e) { + logger.warn("Unable to set external-general-entities on DocumentBuilderFactory; cause: {}", e.getMessage()); + } + try { + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + } catch (ParserConfigurationException e) { + logger.warn("Unable to set external-parameter-entities on DocumentBuilderFactory; cause: {}", e.getMessage()); + } + try { + factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + } catch (ParserConfigurationException e) { + logger.warn("Unable to set load-external-dtd on DocumentBuilderFactory; cause: {}", e.getMessage()); + } + factory.setXIncludeAware(false); + factory.setExpandEntityReferences(false); + factory.setNamespaceAware(true); + factory.setValidating(false); + + return factory; + } + + /** + * Returns a shared {@link DocumentBuilderFactory} configured with secure defaults. + *

+ * Creating XML factories is potentially a pretty expensive operation. Using a shared instance helps to amortize + * this initialization cost via reuse. + * + * @return a securely configured {@link DocumentBuilderFactory} + * + * @since 8.1.0 + * + * @see #makeNewDocumentBuilderFactory() if you really (really?) need a non-shared instance + */ + public static DocumentBuilderFactory getDocumentBuilderFactory() { + return cachedDocumentBuilderFactory.get(); + } + /** * Returns a shared {@link XMLOutputFactory}. This factory will have its * {@link XMLOutputFactory#IS_REPAIRING_NAMESPACES} property set to {@code true}. @@ -88,31 +146,12 @@ public static TransformerFactory makeNewTransformerFactory() { * * @throws FactoryConfigurationError see {@link XMLOutputFactory#newInstance()} * - * @see #makeNewOutputFactory() if you really (really?) need an non-shared instance + * @see #makeNewOutputFactory() if you really (really?) need a non-shared instance */ public static XMLOutputFactory getOutputFactory() { return cachedOutputFactory.get(); } - /** - * Represents a supplier of results. - * - *

There is no requirement that a new or distinct result be returned each - * time the supplier is invoked. - * - * @param the type of results supplied by this supplier - */ - // TODO replace with java.util.function.Supplier after Java 8 migration - interface Supplier { - - /** - * Gets a result. - * - * @return a result - */ - T get(); - } - /** * A supplier that caches results per thread. *

@@ -129,7 +168,7 @@ interface Supplier { */ private static class CachedInstancePerThreadSupplier implements Supplier { - private final ThreadLocal> cachedInstances = new ThreadLocal>(); + private final ThreadLocal> cachedInstances = new ThreadLocal<>(); /** * The underlying supplier, invoked to originally retrieve the per-thread result @@ -167,7 +206,7 @@ public T get() { } // ... and retain it for later re-use - cachedInstances.set(new SoftReference(cachedInstance)); + cachedInstances.set(new SoftReference<>(cachedInstance)); } return cachedInstance; diff --git a/marklogic-client-api/src/main/java/com/marklogic/client/io/DOMHandle.java b/marklogic-client-api/src/main/java/com/marklogic/client/io/DOMHandle.java index f06846fd1..90d8c0fc4 100644 --- a/marklogic-client-api/src/main/java/com/marklogic/client/io/DOMHandle.java +++ b/marklogic-client-api/src/main/java/com/marklogic/client/io/DOMHandle.java @@ -1,25 +1,11 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.io; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.charset.StandardCharsets; - -import javax.xml.XMLConstants; -import javax.xml.namespace.QName; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; - +import com.marklogic.client.MarkLogicIOException; +import com.marklogic.client.MarkLogicInternalException; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.io.marker.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,15 +13,14 @@ import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import org.w3c.dom.ls.DOMImplementationLS; -import org.w3c.dom.ls.LSException; -import org.w3c.dom.ls.LSInput; -import org.w3c.dom.ls.LSOutput; -import org.w3c.dom.ls.LSParser; -import org.w3c.dom.ls.LSResourceResolver; +import org.w3c.dom.ls.*; -import com.marklogic.client.MarkLogicIOException; -import com.marklogic.client.MarkLogicInternalException; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.*; +import java.io.*; +import java.nio.charset.StandardCharsets; /** * A DOM Handle represents XML content as a DOM document for reading or writing. @@ -199,7 +184,7 @@ public String toString() { */ public DocumentBuilderFactory getFactory() throws ParserConfigurationException { if (factory == null) - factory = makeDocumentBuilderFactory(); + factory = XmlFactories.getDocumentBuilderFactory(); return factory; } /** @@ -209,32 +194,6 @@ public DocumentBuilderFactory getFactory() throws ParserConfigurationException { public void setFactory(DocumentBuilderFactory factory) { this.factory = factory; } - protected DocumentBuilderFactory makeDocumentBuilderFactory() throws ParserConfigurationException { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - // default to best practices for conservative security including recommendations per - // https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.md - try { - factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - } catch (ParserConfigurationException e) {} - try { - factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - } catch (ParserConfigurationException e) {} - try { - factory.setFeature("http://xml.org/sax/features/external-general-entities", false); - } catch (ParserConfigurationException e) {} - try { - factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - } catch (ParserConfigurationException e) {} - try { - factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - } catch (ParserConfigurationException e) {} - factory.setXIncludeAware(false); - factory.setExpandEntityReferences(false); - factory.setNamespaceAware(true); - factory.setValidating(false); - - return factory; - } /** * Get the processor used to evaluate XPath expressions. diff --git a/marklogic-client-api/src/main/java/com/marklogic/client/io/DocumentMetadataHandle.java b/marklogic-client-api/src/main/java/com/marklogic/client/io/DocumentMetadataHandle.java index 643e76ca4..30582b82b 100644 --- a/marklogic-client-api/src/main/java/com/marklogic/client/io/DocumentMetadataHandle.java +++ b/marklogic-client-api/src/main/java/com/marklogic/client/io/DocumentMetadataHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.io; @@ -577,10 +577,7 @@ protected void receiveContent(InputStream content) { Document document = null; if (content != null) { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - DocumentBuilder builder = factory.newDocumentBuilder(); + DocumentBuilder builder = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder(); document = builder.parse(new InputSource(new InputStreamReader(content, StandardCharsets.UTF_8))); content.close(); } diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/BufferableHandleTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/BufferableHandleTest.java index 73f9d6c19..5c2e7e756 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/BufferableHandleTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/BufferableHandleTest.java @@ -1,11 +1,14 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.io.*; import com.marklogic.client.test.util.Referred; import com.marklogic.client.test.util.Refers; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; import org.custommonkey.xmlunit.SimpleNamespaceContext; import org.custommonkey.xmlunit.XMLUnit; import org.custommonkey.xmlunit.XpathEngine; @@ -17,16 +20,14 @@ import org.w3c.dom.Element; import org.xml.sax.SAXException; -import jakarta.xml.bind.JAXBContext; -import jakarta.xml.bind.JAXBException; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.util.HashMap; import java.util.Map; import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class BufferableHandleTest { static private XpathEngine xpather; @@ -61,11 +62,7 @@ public void testReadWrite() throws JAXBException, ParserConfigurationException, SAXException, IOException, XpathException { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - - Document domDocument = factory.newDocumentBuilder().newDocument(); + Document domDocument = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder().newDocument(); Element root = domDocument.createElement("root"); root.setAttribute("xml:lang", "en"); root.setAttribute("foo", "bar"); diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/Common.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/Common.java index b5a45af95..26c01ec61 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/Common.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/Common.java @@ -9,6 +9,7 @@ import com.marklogic.client.DatabaseClientBuilder; import com.marklogic.client.DatabaseClientFactory; import com.marklogic.client.extra.okhttpclient.OkHttpClientConfigurator; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.impl.okhttp.RetryIOExceptionInterceptor; import com.marklogic.client.io.DocumentMetadataHandle; import com.marklogic.mgmt.ManageClient; @@ -228,10 +229,7 @@ public static String testDocumentToString(Document document) { public static Document testStringToDocument(String document) { try { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - return factory.newDocumentBuilder().parse( + return XmlFactories.getDocumentBuilderFactory().newDocumentBuilder().parse( new InputSource(new StringReader(document))); } catch (SAXException e) { throw new RuntimeException(e); diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/DeleteSearchTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/DeleteSearchTest.java index 901655e81..3012f3800 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/DeleteSearchTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/DeleteSearchTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test; @@ -7,6 +7,7 @@ import com.marklogic.client.document.DocumentDescriptor; import com.marklogic.client.document.GenericDocumentManager; import com.marklogic.client.document.XMLDocumentManager; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.io.DOMHandle; import com.marklogic.client.query.DeleteQueryDefinition; import com.marklogic.client.query.QueryManager; @@ -15,8 +16,6 @@ import org.w3c.dom.Element; import org.w3c.dom.ls.DOMImplementationLS; -import javax.xml.parsers.DocumentBuilderFactory; - import static org.junit.jupiter.api.Assertions.*; @TestMethodOrder(MethodOrderer.MethodName.class) @@ -32,11 +31,7 @@ public static void beforeClass() throws Exception { } public static void writeDoc() throws Exception { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - - Document domDocument = factory.newDocumentBuilder().newDocument(); + Document domDocument = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder().newDocument(); Element root = domDocument.createElement("root"); root.setAttribute("xml:lang", "en"); root.setAttribute("foo", "bar"); @@ -45,7 +40,7 @@ public static void writeDoc() throws Exception { domDocument.appendChild(root); @SuppressWarnings("unused") - String domString = ((DOMImplementationLS) factory.newDocumentBuilder() + String domString = ((DOMImplementationLS) XmlFactories.getDocumentBuilderFactory().newDocumentBuilder() .getDOMImplementation()).createLSSerializer().writeToString(domDocument); XMLDocumentManager docMgr = client.newXMLDocumentManager(); @@ -61,7 +56,7 @@ public void test_A_Delete() { GenericDocumentManager docMgr = client.newDocumentManager(); DocumentDescriptor desc = docMgr.exists(docId); assertNotNull(desc); - assertEquals(desc.getUri(), docId); + assertEquals(docId, desc.getUri()); QueryManager queryMgr = client.newQueryManager(); DeleteQueryDefinition qdef = queryMgr.newDeleteDefinition(); diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/EvalTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/EvalTest.java index fc9599425..17f76ee5c 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/EvalTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/EvalTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test; @@ -18,21 +18,20 @@ import com.marklogic.client.eval.EvalResultIterator; import com.marklogic.client.eval.ServerEvaluationCall; import com.marklogic.client.impl.HandleAccessor; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.io.*; import com.marklogic.client.query.DeleteQueryDefinition; import com.marklogic.client.query.QueryManager; -import com.marklogic.mgmt.ManageClient; import com.marklogic.mgmt.resource.appservers.ServerManager; +import jakarta.xml.bind.DatatypeConverter; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.w3c.dom.Document; import org.xml.sax.SAXException; -import jakarta.xml.bind.DatatypeConverter; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.BufferedReader; import java.io.IOException; @@ -257,12 +256,9 @@ public void getNullTests() throws DatatypeConfigurationException, JsonProcessing } private void runAndTestXQuery(ServerEvaluationCall call) - throws JsonProcessingException, IOException, SAXException, ParserConfigurationException, DatatypeConfigurationException + throws IOException, SAXException, ParserConfigurationException, DatatypeConfigurationException { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - Document document = factory.newDocumentBuilder() + Document document = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder() .parse(this.getClass().getClassLoader().getResourceAsStream("1-empty-1.0.xml")); call = call.addNamespace("myPrefix", "http://marklogic.com/test") .addVariable("myPrefix:myString", "Mars") diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/GeospatialRegionQueriesTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/GeospatialRegionQueriesTest.java index a9d60fdeb..2adb961d1 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/GeospatialRegionQueriesTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/GeospatialRegionQueriesTest.java @@ -1,11 +1,12 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test; import com.marklogic.client.admin.QueryOptionsManager; import com.marklogic.client.document.DocumentWriteSet; import com.marklogic.client.document.XMLDocumentManager; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.io.DOMHandle; import com.marklogic.client.io.SearchHandle; import com.marklogic.client.io.StringHandle; @@ -19,7 +20,6 @@ import org.w3c.dom.Element; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -54,10 +54,7 @@ private static void buildEnvironment() throws ParserConfigurationException { XMLDocumentManager docMgr = Common.client.newXMLDocumentManager(); DocumentWriteSet writeset =docMgr.newWriteSet(); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - DocumentBuilder documentBldr = factory.newDocumentBuilder(); + DocumentBuilder documentBldr = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder(); Document domDocument = documentBldr.newDocument(); Element root = domDocument.createElement("country"); diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/HandleAsTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/HandleAsTest.java index 4ca6f1604..178ebc9f8 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/HandleAsTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/HandleAsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test; @@ -31,7 +31,6 @@ import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; @@ -124,10 +123,7 @@ public void testBuiltinReadWrite() String xmlDocId = "/test/testAs1.xml"; XMLDocumentManager xmlMgr = Common.client.newXMLDocumentManager(); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - DocumentBuilder xmlDocBldr = factory.newDocumentBuilder(); + DocumentBuilder xmlDocBldr = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder(); Document beforeDocument = xmlDocBldr.newDocument(); Element root = beforeDocument.createElement("doc"); diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/PlanGeneratedBase.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/PlanGeneratedBase.java index 151d760ca..1c45af995 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/PlanGeneratedBase.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/PlanGeneratedBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test; @@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.marklogic.client.MarkLogicIOException; import com.marklogic.client.expression.PlanBuilder; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.io.Format; import com.marklogic.client.row.RowManager; import com.marklogic.client.row.RowRecord; @@ -19,7 +20,6 @@ import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -131,11 +131,7 @@ private void checkXML(String testName, String kind, String expectedRaw, RowRecor // TODO: assertions on kind if set assertEquals(Format.XML, row.getContentFormat("t")); assertEquals("application/xml", row.getContentMimetype("t")); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setCoalescing(true); - factory.setNamespaceAware(true); - factory.setValidating(false); - DocumentBuilder builder = factory.newDocumentBuilder(); + DocumentBuilder builder = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder(); Document expected = builder.parse(new ByteArrayInputStream(expectedRaw.getBytes())); Document actual = row.getContentAs("t", Document.class); diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/QueryOptionsManagerTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/QueryOptionsManagerTest.java index 80c6a1852..603e8919a 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/QueryOptionsManagerTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/QueryOptionsManagerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test; @@ -9,7 +9,9 @@ import com.marklogic.client.ResourceNotFoundException; import com.marklogic.client.ResourceNotResendableException; import com.marklogic.client.admin.QueryOptionsManager; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.io.*; +import jakarta.xml.bind.JAXBException; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -17,14 +19,10 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.ls.DOMImplementationLS; -import org.xml.sax.SAXException; -import jakarta.xml.bind.JAXBException; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.File; -import java.io.IOException; import static org.junit.jupiter.api.Assertions.*; @@ -60,14 +58,11 @@ public void testQueryOptionsManager() @Test public void testXMLDocsAsSearchOptions() - throws ParserConfigurationException, SAXException, IOException, ResourceNotFoundException, ForbiddenUserException, FailedRequestException, ResourceNotResendableException + throws ParserConfigurationException, ResourceNotFoundException, ForbiddenUserException, FailedRequestException, ResourceNotResendableException { String optionsName = "invalid"; - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - DocumentBuilder documentBldr = factory.newDocumentBuilder(); + DocumentBuilder documentBldr = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder(); Document domDocument = documentBldr.newDocument(); Element root = domDocument.createElementNS("http://marklogic.com/appservices/search","options"); diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/RawQueryDefinitionTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/RawQueryDefinitionTest.java index 90cc36741..f8c8500c5 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/RawQueryDefinitionTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/RawQueryDefinitionTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test; @@ -11,6 +11,7 @@ import com.marklogic.client.admin.QueryOptionsManager; import com.marklogic.client.document.JSONDocumentManager; import com.marklogic.client.document.XMLDocumentManager; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.io.*; import com.marklogic.client.io.marker.StructureWriteHandle; import com.marklogic.client.query.*; @@ -25,7 +26,6 @@ import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -541,10 +541,7 @@ public void test_issue581_RawStructuredQueryFromFileHandle() throws Exception { } private static Document parseXml(String xml) throws Exception { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - DocumentBuilder builder = factory.newDocumentBuilder(); + DocumentBuilder builder = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder(); Document document = builder.parse(new InputSource(new StringReader(xml))); return document; } diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/RequestLoggerTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/RequestLoggerTest.java index 8277a25ce..fe9810e8e 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/RequestLoggerTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/RequestLoggerTest.java @@ -1,10 +1,11 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test; import com.marklogic.client.document.XMLDocumentManager; import com.marklogic.client.impl.OutputStreamTee; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.io.DOMHandle; import com.marklogic.client.io.SearchHandle; import com.marklogic.client.io.StringHandle; @@ -20,11 +21,11 @@ import org.w3c.dom.ls.DOMImplementationLS; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.*; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; public class RequestLoggerTest { @BeforeAll @@ -81,13 +82,10 @@ public void testCopyTee() throws IOException { } @Test - public void testWriteReadLog() throws IOException, ParserConfigurationException { + public void testWriteReadLog() throws ParserConfigurationException { String docId = "/test/testWrite1.xml"; - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - DocumentBuilder documentBldr = factory.newDocumentBuilder(); + DocumentBuilder documentBldr = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder(); Document domDocument = documentBldr.newDocument(); Element root = domDocument.createElement("root"); root.setAttribute("xml:lang", "en"); diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/SearchFacetTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/SearchFacetTest.java index fb55b5274..89909c199 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/SearchFacetTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/SearchFacetTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test; @@ -8,6 +8,7 @@ import com.marklogic.client.ResourceNotFoundException; import com.marklogic.client.ResourceNotResendableException; import com.marklogic.client.admin.QueryOptionsManager; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.io.DOMHandle; import com.marklogic.client.io.SearchHandle; import com.marklogic.client.query.FacetResult; @@ -21,7 +22,6 @@ import org.xml.sax.SAXException; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.IOException; import java.io.StringReader; @@ -124,10 +124,7 @@ public void testFacetSearch() throws IOException, ParserConfigurationException, SAXException, FailedRequestException, ForbiddenUserException, ResourceNotFoundException, ResourceNotResendableException { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - DocumentBuilder builder = factory.newDocumentBuilder(); + DocumentBuilder builder = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder(); Document document = builder.parse(new InputSource(new StringReader(options))); mgr = Common.restAdminClient.newServerConfigManager().newQueryOptionsManager(); diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/XMLDocumentTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/XMLDocumentTest.java index 6bfde88fe..44e1b16d0 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/XMLDocumentTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/XMLDocumentTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test; @@ -27,7 +27,6 @@ import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLStreamException; @@ -81,10 +80,7 @@ public void testReadWrite() { String docId = "/test/testWrite1.xml"; - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - Document domDocument = factory.newDocumentBuilder().newDocument(); + Document domDocument = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder().newDocument(); Element root = domDocument.createElement("root"); root.setAttribute("xml:lang", "en"); root.setAttribute("foo", "bar"); @@ -355,10 +351,7 @@ public void testPatch() throws Exception { DocumentPatchHandle patchHandle = patchBldr.build(); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - DocumentBuilder documentBldr = factory.newDocumentBuilder(); + DocumentBuilder documentBldr = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder(); for (int i=0; i < 2; i++) { Document domDocument = documentBldr.newDocument(); Element root = domDocument.createElement("root"); diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/datamovement/LegalHoldsTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/datamovement/LegalHoldsTest.java index 48c6bb7c7..b332f3395 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/datamovement/LegalHoldsTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/datamovement/LegalHoldsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test.datamovement; @@ -88,7 +88,7 @@ public void scenario10() throws Exception { // TODO This test failed when 2022 became 2023; increasing -7 to a higher number fixed it. The test could obviously // use some rework to ensure that it doesn't fail every time the year changes, but this comment is being left here // so that if/when this does fail in the future, it'll be easy to fix. - date.roll(Calendar.YEAR, -10); + date.roll(Calendar.YEAR, -11); StructuredQueryBuilder sqb = new StructuredQueryBuilder(); StructuredQueryDefinition query = sqb.and( diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/datamovement/ScenariosTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/datamovement/ScenariosTest.java index c20a2181c..ab2001c9a 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/datamovement/ScenariosTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/datamovement/ScenariosTest.java @@ -1,10 +1,11 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test.datamovement; import com.marklogic.client.DatabaseClient; import com.marklogic.client.datamovement.*; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.io.DOMHandle; import com.marklogic.client.test.Common; import org.junit.jupiter.api.AfterAll; @@ -14,7 +15,6 @@ import org.w3c.dom.Document; import org.w3c.dom.Element; -import javax.xml.parsers.DocumentBuilderFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -64,10 +64,8 @@ private class Message { public Map getBody() throws Exception { Map map = new HashMap<>(); map.put("uri", "http://marklogic.com/my/test/uri"); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - Document document = factory.newDocumentBuilder().newDocument(); + + Document document = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder().newDocument(); Element element = document.createElement("test"); document.appendChild(element); map.put("content", document); diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/io/DocumentMetadataHandleTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/io/DocumentMetadataHandleTest.java index ac427b445..a2d5087eb 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/io/DocumentMetadataHandleTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/io/DocumentMetadataHandleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. */ package com.marklogic.client.test.io; @@ -7,6 +7,7 @@ import com.marklogic.client.document.BinaryDocumentManager; import com.marklogic.client.document.DocumentManager.Metadata; import com.marklogic.client.document.XMLDocumentManager; +import com.marklogic.client.impl.XmlFactories; import com.marklogic.client.io.DocumentMetadataHandle; import com.marklogic.client.io.DocumentMetadataHandle.*; import com.marklogic.client.io.FileHandle; @@ -27,7 +28,6 @@ import org.xml.sax.SAXException; import javax.xml.namespace.QName; -import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.File; import java.io.FileInputStream; @@ -88,10 +88,7 @@ public void testReadWriteMetadata() throws SAXException, IOException, XpathExcep ""+ ""; - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(false); - Document document = factory.newDocumentBuilder().newDocument(); + Document document = XmlFactories.getDocumentBuilderFactory().newDocumentBuilder().newDocument(); Element third = document.createElement("third"); Element child = document.createElement("third.first"); child.setTextContent("value third one");