This is an automated email from the ASF dual-hosted git repository.

ppkarwasz pushed a commit to branch feature/jaxp-factory-methods
in repository https://gitbox.apache.org/repos/asf/commons-xml.git

commit 032c62f635c37f93edddd10a46b39b79b5eeec8d
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Fri Aug 28 08:41:11 2026 +0200

    Emulate the Java 13 NSInstance methods and reuse them internally
    
    The JDK implements the newNSInstance family by enabling namespace
    awareness on the result of the plain lookup; do the same with a private
    makeNSAware helper instead of resolving the platform methods through
    MethodHandles, and route the internal namespace-aware parser
    construction in newHardenedReader, hardenSourceToDom and
    HardeningXPath.parse through the public newNSInstance() methods.
    
    Assisted-By: Claude Fable 5 <[email protected]>
    Claude-Session: https://claude.ai/code/session_01ErRKq7RUeQ9LGrSboSUyYm
---
 .../xml/HardeningDocumentBuilderFactory.java       | 88 +++++----------------
 .../commons/xml/HardeningSAXParserFactory.java     | 91 +++++-----------------
 .../commons/xml/HardeningTransformerFactory.java   |  3 +-
 .../org/apache/commons/xml/HardeningXPath.java     |  3 +-
 4 files changed, 44 insertions(+), 141 deletions(-)

diff --git 
a/src/main/java/org/apache/commons/xml/HardeningDocumentBuilderFactory.java 
b/src/main/java/org/apache/commons/xml/HardeningDocumentBuilderFactory.java
index aee284c..1c16de6 100644
--- a/src/main/java/org/apache/commons/xml/HardeningDocumentBuilderFactory.java
+++ b/src/main/java/org/apache/commons/xml/HardeningDocumentBuilderFactory.java
@@ -56,13 +56,6 @@ public final class HardeningDocumentBuilderFactory {
 
     private static final MethodHandle NEW_DEFAULT_INSTANCE = 
findStatic("newDefaultInstance", 
MethodType.methodType(DocumentBuilderFactory.class));
 
-    private static final MethodHandle NEW_DEFAULT_NS_INSTANCE = 
findStatic("newDefaultNSInstance", 
MethodType.methodType(DocumentBuilderFactory.class));
-
-    private static final MethodHandle NEW_NS_INSTANCE = 
findStatic("newNSInstance", 
MethodType.methodType(DocumentBuilderFactory.class));
-
-    private static final MethodHandle NEW_NS_INSTANCE_BY_CLASS_NAME = 
findStatic("newNSInstance",
-            MethodType.methodType(DocumentBuilderFactory.class, String.class, 
ClassLoader.class));
-
     private static MethodHandle findStatic(final String name, final MethodType 
type) {
         try {
             return 
MethodHandles.publicLookup().findStatic(DocumentBuilderFactory.class, name, 
type);
@@ -104,6 +97,17 @@ static DocumentBuilderFactory harden(final 
DocumentBuilderFactory factory) {
         return new Wrapper(factory);
     }
 
+    /**
+     * Enables namespace awareness on the given factory; the {@code 
NSInstance} counterpart of each factory method routes its result through here.
+     *
+     * @param factory the factory to configure; never {@code null}.
+     * @return The given factory, namespace-aware.
+     */
+    private static DocumentBuilderFactory makeNSAware(final 
DocumentBuilderFactory factory) {
+        factory.setNamespaceAware(true);
+        return factory;
+    }
+
     /**
      * Returns a new, hardened {@link DocumentBuilderFactory} of the 
system-default implementation.
      * <p>
@@ -135,11 +139,8 @@ public static DocumentBuilderFactory newDefaultInstance() {
     }
 
     /**
-     * Returns a new, hardened, namespace-aware {@link DocumentBuilderFactory} 
of the system-default implementation.
-     * <p>
-     * Obtained as by {@code DocumentBuilderFactory.newDefaultNSInstance()} 
where the platform provides it (Java 13 or later), and by enabling namespace
-     * awareness on {@link #newDefaultInstance()} otherwise, the behavior the 
JAXP method is specified to have.
-     * </p>
+     * Returns a new, hardened, namespace-aware {@link DocumentBuilderFactory} 
of the system-default implementation, enabling namespace awareness on
+     * {@link #newDefaultInstance()}, the behavior {@code 
DocumentBuilderFactory.newDefaultNSInstance()} (Java 13 or later) is specified 
to have.
      *
      * @return A hardened, namespace-aware factory.
      * @throws IllegalStateException     Thrown if a required hardening 
setting cannot be applied to the underlying implementation.
@@ -147,21 +148,7 @@ public static DocumentBuilderFactory newDefaultInstance() {
      *                                   (for example Android).
      */
     public static DocumentBuilderFactory newDefaultNSInstance() {
-        if (NEW_DEFAULT_NS_INSTANCE != null) {
-            final DocumentBuilderFactory factory;
-            try {
-                factory = (DocumentBuilderFactory) 
NEW_DEFAULT_NS_INSTANCE.invokeExact();
-            } catch (final FactoryConfigurationError e) {
-                throw e;
-            } catch (final Throwable e) {
-                // Unreachable: the looked-up method declares no other 
exceptions.
-                throw new IllegalStateException(e);
-            }
-            return harden(factory);
-        }
-        final DocumentBuilderFactory factory = newDefaultInstance();
-        factory.setNamespaceAware(true);
-        return factory;
+        return makeNSAware(newDefaultInstance());
     }
 
     /**
@@ -194,11 +181,8 @@ public static DocumentBuilderFactory newInstance(final 
String factoryClassName,
     }
 
     /**
-     * Returns a new, hardened, namespace-aware {@link DocumentBuilderFactory}.
-     * <p>
-     * Obtained as by {@code DocumentBuilderFactory.newNSInstance()} where the 
platform provides it (Java 13 or later), and by enabling namespace awareness on
-     * {@link #newInstance()} otherwise, the behavior the JAXP method is 
specified to have.
-     * </p>
+     * Returns a new, hardened, namespace-aware {@link 
DocumentBuilderFactory}, enabling namespace awareness on {@link 
#newInstance()}, the behavior
+     * {@code DocumentBuilderFactory.newNSInstance()} (Java 13 or later) is 
specified to have.
      *
      * @return A hardened, namespace-aware factory.
      * @throws IllegalStateException     Thrown if a required hardening 
setting cannot be applied to the underlying implementation.
@@ -206,29 +190,13 @@ public static DocumentBuilderFactory newInstance(final 
String factoryClassName,
      *                                   implementation is not available or 
cannot be instantiated.
      */
     public static DocumentBuilderFactory newNSInstance() {
-        if (NEW_NS_INSTANCE != null) {
-            final DocumentBuilderFactory factory;
-            try {
-                factory = (DocumentBuilderFactory) 
NEW_NS_INSTANCE.invokeExact();
-            } catch (final FactoryConfigurationError e) {
-                throw e;
-            } catch (final Throwable e) {
-                // Unreachable: the looked-up method declares no other 
exceptions.
-                throw new IllegalStateException(e);
-            }
-            return harden(factory);
-        }
-        final DocumentBuilderFactory factory = newInstance();
-        factory.setNamespaceAware(true);
-        return factory;
+        return makeNSAware(newInstance());
     }
 
     /**
-     * Returns a new, hardened, namespace-aware {@link DocumentBuilderFactory} 
of the given implementation class.
-     * <p>
-     * Obtained as by {@code DocumentBuilderFactory.newNSInstance(String, 
ClassLoader)} where the platform provides it (Java 13 or later), and by enabling
-     * namespace awareness on {@link #newInstance(String, ClassLoader)} 
otherwise, the behavior the JAXP method is specified to have.
-     * </p>
+     * Returns a new, hardened, namespace-aware {@link DocumentBuilderFactory} 
of the given implementation class, enabling namespace awareness on
+     * {@link #newInstance(String, ClassLoader)}, the behavior {@code 
DocumentBuilderFactory.newNSInstance(String, ClassLoader)} (Java 13 or later) 
is specified
+     * to have.
      *
      * @param factoryClassName The fully qualified class name of the {@link 
DocumentBuilderFactory} implementation.
      * @param classLoader      The class loader used to load the factory 
class; {@code null} means the current thread's context class loader.
@@ -237,21 +205,7 @@ public static DocumentBuilderFactory newNSInstance() {
      * @throws FactoryConfigurationError Thrown if {@code factoryClassName} is 
{@code null} or the factory class cannot be loaded or instantiated.
      */
     public static DocumentBuilderFactory newNSInstance(final String 
factoryClassName, final ClassLoader classLoader) {
-        if (NEW_NS_INSTANCE_BY_CLASS_NAME != null) {
-            final DocumentBuilderFactory factory;
-            try {
-                factory = (DocumentBuilderFactory) 
NEW_NS_INSTANCE_BY_CLASS_NAME.invokeExact(factoryClassName, classLoader);
-            } catch (final FactoryConfigurationError e) {
-                throw e;
-            } catch (final Throwable e) {
-                // Unreachable: the looked-up method declares no other 
exceptions.
-                throw new IllegalStateException(e);
-            }
-            return harden(factory);
-        }
-        final DocumentBuilderFactory factory = newInstance(factoryClassName, 
classLoader);
-        factory.setNamespaceAware(true);
-        return factory;
+        return makeNSAware(newInstance(factoryClassName, classLoader));
     }
 
     /**
diff --git 
a/src/main/java/org/apache/commons/xml/HardeningSAXParserFactory.java 
b/src/main/java/org/apache/commons/xml/HardeningSAXParserFactory.java
index 36d4585..9101acd 100644
--- a/src/main/java/org/apache/commons/xml/HardeningSAXParserFactory.java
+++ b/src/main/java/org/apache/commons/xml/HardeningSAXParserFactory.java
@@ -66,13 +66,6 @@ public final class HardeningSAXParserFactory {
 
     private static final MethodHandle NEW_DEFAULT_INSTANCE = 
findStatic("newDefaultInstance", MethodType.methodType(SAXParserFactory.class));
 
-    private static final MethodHandle NEW_DEFAULT_NS_INSTANCE = 
findStatic("newDefaultNSInstance", 
MethodType.methodType(SAXParserFactory.class));
-
-    private static final MethodHandle NEW_NS_INSTANCE = 
findStatic("newNSInstance", MethodType.methodType(SAXParserFactory.class));
-
-    private static final MethodHandle NEW_NS_INSTANCE_BY_CLASS_NAME = 
findStatic("newNSInstance",
-            MethodType.methodType(SAXParserFactory.class, String.class, 
ClassLoader.class));
-
     private static MethodHandle findStatic(final String name, final MethodType 
type) {
         try {
             return 
MethodHandles.publicLookup().findStatic(SAXParserFactory.class, name, type);
@@ -161,6 +154,17 @@ static XMLReader harden(final XMLReader reader) {
         return new HardeningXMLReader(reader);
     }
 
+    /**
+     * Enables namespace awareness on the given factory; the {@code 
NSInstance} counterpart of each factory method routes its result through here.
+     *
+     * @param factory the factory to configure; never {@code null}.
+     * @return The given factory, namespace-aware.
+     */
+    private static SAXParserFactory makeNSAware(final SAXParserFactory 
factory) {
+        factory.setNamespaceAware(true);
+        return factory;
+    }
+
     /**
      * Returns a new, hardened {@link SAXParserFactory} of the system-default 
implementation.
      * <p>
@@ -192,11 +196,8 @@ public static SAXParserFactory newDefaultInstance() {
     }
 
     /**
-     * Returns a new, hardened, namespace-aware {@link SAXParserFactory} of 
the system-default implementation.
-     * <p>
-     * Obtained as by {@code SAXParserFactory.newDefaultNSInstance()} where 
the platform provides it (Java 13 or later), and by enabling namespace 
awareness on
-     * {@link #newDefaultInstance()} otherwise, the behavior the JAXP method 
is specified to have.
-     * </p>
+     * Returns a new, hardened, namespace-aware {@link SAXParserFactory} of 
the system-default implementation, enabling namespace awareness on
+     * {@link #newDefaultInstance()}, the behavior {@code 
SAXParserFactory.newDefaultNSInstance()} (Java 13 or later) is specified to 
have.
      *
      * @return A hardened, namespace-aware factory.
      * @throws IllegalStateException     Thrown if a required hardening 
setting cannot be applied to the underlying implementation.
@@ -204,21 +205,7 @@ public static SAXParserFactory newDefaultInstance() {
      *                                   (for example Android).
      */
     public static SAXParserFactory newDefaultNSInstance() {
-        if (NEW_DEFAULT_NS_INSTANCE != null) {
-            final SAXParserFactory factory;
-            try {
-                factory = (SAXParserFactory) 
NEW_DEFAULT_NS_INSTANCE.invokeExact();
-            } catch (final FactoryConfigurationError e) {
-                throw e;
-            } catch (final Throwable e) {
-                // Unreachable: the looked-up method declares no other 
exceptions.
-                throw new IllegalStateException(e);
-            }
-            return harden(factory);
-        }
-        final SAXParserFactory factory = newDefaultInstance();
-        factory.setNamespaceAware(true);
-        return factory;
+        return makeNSAware(newDefaultInstance());
     }
 
     /**
@@ -231,9 +218,7 @@ public static SAXParserFactory newDefaultNSInstance() {
      */
     static XMLReader newHardenedReader() throws 
TransformerConfigurationException {
         try {
-            final SAXParserFactory factory = 
harden(SAXParserFactory.newInstance());
-            factory.setNamespaceAware(true);
-            return factory.newSAXParser().getXMLReader();
+            return newNSInstance().newSAXParser().getXMLReader();
         } catch (final ParserConfigurationException | SAXException e) {
             throw new TransformerConfigurationException("Failed to obtain a 
hardened XMLReader for source parsing", e);
         }
@@ -265,11 +250,8 @@ public static SAXParserFactory newInstance(final String 
factoryClassName, final
     }
 
     /**
-     * Returns a new, hardened, namespace-aware {@link SAXParserFactory}.
-     * <p>
-     * Obtained as by {@code SAXParserFactory.newNSInstance()} where the 
platform provides it (Java 13 or later), and by enabling namespace awareness on
-     * {@link #newInstance()} otherwise, the behavior the JAXP method is 
specified to have.
-     * </p>
+     * Returns a new, hardened, namespace-aware {@link SAXParserFactory}, 
enabling namespace awareness on {@link #newInstance()}, the behavior
+     * {@code SAXParserFactory.newNSInstance()} (Java 13 or later) is 
specified to have.
      *
      * @return A hardened, namespace-aware factory.
      * @throws IllegalStateException     Thrown if a required hardening 
setting cannot be applied to the underlying implementation.
@@ -277,29 +259,12 @@ public static SAXParserFactory newInstance(final String 
factoryClassName, final
      *                                   error} or if the implementation is 
not available or cannot be instantiated.
      */
     public static SAXParserFactory newNSInstance() {
-        if (NEW_NS_INSTANCE != null) {
-            final SAXParserFactory factory;
-            try {
-                factory = (SAXParserFactory) NEW_NS_INSTANCE.invokeExact();
-            } catch (final FactoryConfigurationError e) {
-                throw e;
-            } catch (final Throwable e) {
-                // Unreachable: the looked-up method declares no other 
exceptions.
-                throw new IllegalStateException(e);
-            }
-            return harden(factory);
-        }
-        final SAXParserFactory factory = newInstance();
-        factory.setNamespaceAware(true);
-        return factory;
+        return makeNSAware(newInstance());
     }
 
     /**
-     * Returns a new, hardened, namespace-aware {@link SAXParserFactory} of 
the given implementation class.
-     * <p>
-     * Obtained as by {@code SAXParserFactory.newNSInstance(String, 
ClassLoader)} where the platform provides it (Java 13 or later), and by 
enabling namespace
-     * awareness on {@link #newInstance(String, ClassLoader)} otherwise, the 
behavior the JAXP method is specified to have.
-     * </p>
+     * Returns a new, hardened, namespace-aware {@link SAXParserFactory} of 
the given implementation class, enabling namespace awareness on
+     * {@link #newInstance(String, ClassLoader)}, the behavior {@code 
SAXParserFactory.newNSInstance(String, ClassLoader)} (Java 13 or later) is 
specified to have.
      *
      * @param factoryClassName The fully qualified class name of the {@link 
SAXParserFactory} implementation.
      * @param classLoader      The class loader used to load the factory 
class; {@code null} means the current thread's context class loader.
@@ -308,21 +273,7 @@ public static SAXParserFactory newNSInstance() {
      * @throws FactoryConfigurationError Thrown if {@code factoryClassName} is 
{@code null} or the factory class cannot be loaded or instantiated.
      */
     public static SAXParserFactory newNSInstance(final String 
factoryClassName, final ClassLoader classLoader) {
-        if (NEW_NS_INSTANCE_BY_CLASS_NAME != null) {
-            final SAXParserFactory factory;
-            try {
-                factory = (SAXParserFactory) 
NEW_NS_INSTANCE_BY_CLASS_NAME.invokeExact(factoryClassName, classLoader);
-            } catch (final FactoryConfigurationError e) {
-                throw e;
-            } catch (final Throwable e) {
-                // Unreachable: the looked-up method declares no other 
exceptions.
-                throw new IllegalStateException(e);
-            }
-            return harden(factory);
-        }
-        final SAXParserFactory factory = newInstance(factoryClassName, 
classLoader);
-        factory.setNamespaceAware(true);
-        return factory;
+        return makeNSAware(newInstance(factoryClassName, classLoader));
     }
 
     private static void setFeature(final SAXParserFactory factory, final 
String feature, final boolean value) {
diff --git 
a/src/main/java/org/apache/commons/xml/HardeningTransformerFactory.java 
b/src/main/java/org/apache/commons/xml/HardeningTransformerFactory.java
index a0ff62f..7f030c5 100644
--- a/src/main/java/org/apache/commons/xml/HardeningTransformerFactory.java
+++ b/src/main/java/org/apache/commons/xml/HardeningTransformerFactory.java
@@ -244,8 +244,7 @@ private static Source hardenSourceToDom(final Source 
source) throws TransformerC
                 final InputSource inputSource = 
SAXSource.sourceToInputSource(source);
                 if (inputSource != null) {
                     try {
-                        final DocumentBuilderFactory factory = 
HardeningDocumentBuilderFactory.harden(DocumentBuilderFactory.newInstance());
-                        factory.setNamespaceAware(true);
+                        final DocumentBuilderFactory factory = 
HardeningDocumentBuilderFactory.newNSInstance();
                         final Document document = 
factory.newDocumentBuilder().parse(inputSource);
                         return new DOMSource(document, 
inputSource.getSystemId());
                     } catch (final ParserConfigurationException | SAXException 
| IOException e) {
diff --git a/src/main/java/org/apache/commons/xml/HardeningXPath.java 
b/src/main/java/org/apache/commons/xml/HardeningXPath.java
index abac0b7..c843fea 100644
--- a/src/main/java/org/apache/commons/xml/HardeningXPath.java
+++ b/src/main/java/org/apache/commons/xml/HardeningXPath.java
@@ -66,8 +66,7 @@ final class HardeningXPath implements XPath {
     static Document parse(final InputSource source) throws 
XPathExpressionException {
         Objects.requireNonNull(source, "source");
         try {
-            final DocumentBuilderFactory factory = 
HardeningDocumentBuilderFactory.harden(DocumentBuilderFactory.newInstance());
-            factory.setNamespaceAware(true);
+            final DocumentBuilderFactory factory = 
HardeningDocumentBuilderFactory.newNSInstance();
             return factory.newDocumentBuilder().parse(source);
         } catch (final ParserConfigurationException | SAXException | 
IOException e) {
             throw new XPathExpressionException(e);

Reply via email to