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

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

commit 9157c8e2971e3aeb08eb2124f1fb00bff635f610
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Sat Apr 25 10:02:58 2026 +0200

    feat: remove UnsupportedXmlImplementationException
    
    `XmlFactories` will throw `HardeningException` in both the following cases:
    
    - The implementation is unsupported,
    - A known implementation unexpectedly does not handle a feature.
---
 README.md                                          |  2 +-
 .../UnsupportedXmlImplementationException.java     | 53 ----------------------
 .../apache/commons/xml/factory/XmlFactories.java   | 18 +++++---
 .../xml/factory/internal/HardeningException.java   | 16 +++++--
 .../xml/factory/internal/ProviderRegistry.java     | 10 ++--
 src/site/markdown/index.md                         |  2 +-
 .../factory/UnsupportedXmlImplementationTest.java  | 10 ++--
 .../xml/factory/internal/ProviderRegistryTest.java | 13 +++---
 8 files changed, 43 insertions(+), 81 deletions(-)

diff --git a/README.md b/README.md
index 9bcec33..e169e91 100644
--- a/README.md
+++ b/README.md
@@ -65,7 +65,7 @@ stylesheet) is blocked, and DOCTYPE input is rejected 
wherever the underlying im
 
 Out of the box the library recognises the stock JDK JAXP implementations, 
Apache Xerces 2.x, Woodstox, and Saxon-HE. If
 a factory resolves to an implementation not covered by any bundled or 
registered provider, every `XmlFactories` method
-throws `UnsupportedXmlImplementationException`.
+throws `IllegalStateException` with a message naming the unsupported class.
 
 Support for additional implementations can be plugged in by publishing an
 `org.apache.commons.xml.factory.spi.XmlProvider` through the standard Java 
`ServiceLoader` mechanism. Bundled providers
diff --git 
a/src/main/java/org/apache/commons/xml/factory/UnsupportedXmlImplementationException.java
 
b/src/main/java/org/apache/commons/xml/factory/UnsupportedXmlImplementationException.java
deleted file mode 100644
index 11ed207..0000000
--- 
a/src/main/java/org/apache/commons/xml/factory/UnsupportedXmlImplementationException.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.commons.xml.factory;
-
-/**
- * Thrown when no {@link org.apache.commons.xml.factory.spi.XmlProvider 
XmlProvider} is able to harden a JAXP factory of the given concrete class.
- */
-public class UnsupportedXmlImplementationException extends 
IllegalStateException {
-
-    private static final long serialVersionUID = 1L;
-
-    private final Class<?> unsupportedFactoryClass;
-
-    /**
-     * Constructs a new exception naming the unsupported factory class.
-     *
-     * <p>The detail message identifies the class and suggests remediation 
steps.</p>
-     *
-     * @param unsupportedFactoryClass the concrete factory class that no 
provider recognises.
-     */
-    public UnsupportedXmlImplementationException(final Class<?> 
unsupportedFactoryClass) {
-        super(buildMessage(unsupportedFactoryClass));
-        this.unsupportedFactoryClass = unsupportedFactoryClass;
-    }
-
-    private static String buildMessage(final Class<?> factoryClass) {
-        return String.format("No XmlProvider supports JAXP factory class %s. 
Add a supported JAXP implementation (for example Apache Xerces) to the " +
-                "classpath, or register a custom XmlProvider via 
META-INF/services/org.apache.commons.xml.factory.spi.XmlProvider.", 
factoryClass.getName());
-    }
-
-    /**
-     * Gets the concrete factory class that no registered provider could 
configure.
-     *
-     * @return the unsupported factory class.
-     */
-    public Class<?> getUnsupportedFactoryClass() {
-        return unsupportedFactoryClass;
-    }
-}
diff --git a/src/main/java/org/apache/commons/xml/factory/XmlFactories.java 
b/src/main/java/org/apache/commons/xml/factory/XmlFactories.java
index 18d63c3..3733d0c 100644
--- a/src/main/java/org/apache/commons/xml/factory/XmlFactories.java
+++ b/src/main/java/org/apache/commons/xml/factory/XmlFactories.java
@@ -70,7 +70,8 @@ public final class XmlFactories {
      * <p>Together these block <strong>every</strong> external reference the 
parser would follow while reading a document through this factory.</p>
      *
      * @return a hardened factory.
-     * @throws UnsupportedXmlImplementationException if the underlying JAXP 
implementation is not recognised by any registered {@link XmlProvider}.
+     * @throws IllegalStateException if no registered {@link XmlProvider} 
recognises the underlying JAXP implementation, or if the recognised provider 
cannot
+     *         apply the hardening settings to it.
      */
     public static DocumentBuilderFactory newDocumentBuilderFactory() {
         final DocumentBuilderFactory factory = 
DocumentBuilderFactory.newInstance();
@@ -91,7 +92,8 @@ public static DocumentBuilderFactory 
newDocumentBuilderFactory() {
      * <p>Together these block <strong>every</strong> external reference the 
parser would follow while reading a document through this factory.</p>
      *
      * @return a hardened factory.
-     * @throws UnsupportedXmlImplementationException if the underlying JAXP 
implementation is not recognised by any registered {@link XmlProvider}.
+     * @throws IllegalStateException if no registered {@link XmlProvider} 
recognises the underlying JAXP implementation, or if the recognised provider 
cannot
+     *         apply the hardening settings to it.
      */
     public static SAXParserFactory newSAXParserFactory() {
         final SAXParserFactory factory = SAXParserFactory.newInstance();
@@ -122,7 +124,8 @@ public static SAXParserFactory newSAXParserFactory() {
      * above.</p>
      *
      * @return a hardened factory.
-     * @throws UnsupportedXmlImplementationException if the underlying Schema 
implementation is not recognised by any registered {@link XmlProvider}.
+     * @throws IllegalStateException if no registered {@link XmlProvider} 
recognises the underlying Schema implementation, or if the recognised provider 
cannot
+     *         apply the hardening settings to it.
      */
     public static SchemaFactory newSchemaFactory() {
         final SchemaFactory factory = 
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
@@ -150,7 +153,8 @@ public static SchemaFactory newSchemaFactory() {
      * {@link javax.xml.transform.sax.SAXSource}.</p>
      *
      * @return a hardened factory.
-     * @throws UnsupportedXmlImplementationException if the underlying TrAX 
implementation is not recognised by any registered {@link XmlProvider}.
+     * @throws IllegalStateException if no registered {@link XmlProvider} 
recognises the underlying TrAX implementation, or if the recognised provider 
cannot
+     *         apply the hardening settings to it.
      */
     public static TransformerFactory newTransformerFactory() {
         final TransformerFactory factory = TransformerFactory.newInstance();
@@ -176,7 +180,8 @@ public static TransformerFactory newTransformerFactory() {
      * {@link XMLInputFactory#IS_VALIDATING}.</p>
      *
      * @return a hardened factory.
-     * @throws UnsupportedXmlImplementationException if the underlying StAX 
implementation is not recognised by any registered {@link XmlProvider}.
+     * @throws IllegalStateException if no registered {@link XmlProvider} 
recognises the underlying StAX implementation, or if the recognised provider 
cannot
+     *         apply the hardening settings to it.
      */
     public static XMLInputFactory newXMLInputFactory() {
         final XMLInputFactory factory = XMLInputFactory.newInstance();
@@ -196,7 +201,8 @@ public static XMLInputFactory newXMLInputFactory() {
      * underlying implementation honours the flag.</p>
      *
      * @return a hardened factory.
-     * @throws UnsupportedXmlImplementationException if the underlying XPath 
implementation is not recognised by any registered {@link XmlProvider}.
+     * @throws IllegalStateException if no registered {@link XmlProvider} 
recognises the underlying XPath implementation, or if the recognised provider 
cannot
+     *         apply the hardening settings to it.
      */
     public static XPathFactory newXPathFactory() {
         final XPathFactory factory = XPathFactory.newInstance();
diff --git 
a/src/main/java/org/apache/commons/xml/factory/internal/HardeningException.java 
b/src/main/java/org/apache/commons/xml/factory/internal/HardeningException.java
index dbfaea9..804dcd1 100644
--- 
a/src/main/java/org/apache/commons/xml/factory/internal/HardeningException.java
+++ 
b/src/main/java/org/apache/commons/xml/factory/internal/HardeningException.java
@@ -17,10 +17,16 @@
 package org.apache.commons.xml.factory.internal;
 
 /**
- * Thrown when a provider cannot fully harden a factory.
+ * Thrown when a factory cannot be hardened.
  *
- * <p>The message names the specific feature or property that failed; the 
cause is the original checked or unchecked exception from the JAXP
- * implementation.</p>
+ * <p>Two failure modes share this type:</p>
+ * <ul>
+ *   <li>No registered {@link org.apache.commons.xml.factory.spi.XmlProvider 
XmlProvider} recognises the concrete factory class.</li>
+ *   <li>A recognised provider tried to apply a hardening setting and the 
implementation rejected it.</li>
+ * </ul>
+ *
+ * <p>The message names the unsupported factory class or the specific feature, 
attribute or property that failed; the cause, when present, is the original
+ * checked or unchecked exception from the JAXP implementation.</p>
  *
  * <p>Package-private by design: callers should catch {@link 
IllegalStateException}, which this extends.</p>
  */
@@ -28,6 +34,10 @@ class HardeningException extends IllegalStateException {
 
     private static final long serialVersionUID = 1L;
 
+    HardeningException(final String message) {
+        super(message);
+    }
+
     HardeningException(final String message, final Throwable cause) {
         super(message, cause);
     }
diff --git 
a/src/main/java/org/apache/commons/xml/factory/internal/ProviderRegistry.java 
b/src/main/java/org/apache/commons/xml/factory/internal/ProviderRegistry.java
index 2adf613..5dad3b5 100644
--- 
a/src/main/java/org/apache/commons/xml/factory/internal/ProviderRegistry.java
+++ 
b/src/main/java/org/apache/commons/xml/factory/internal/ProviderRegistry.java
@@ -25,7 +25,6 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
-import org.apache.commons.xml.factory.UnsupportedXmlImplementationException;
 import org.apache.commons.xml.factory.spi.XmlProvider;
 
 /**
@@ -36,7 +35,7 @@
  * <ol>
  *   <li>Bundled providers in a fixed order: {@link StockJdkProvider}, {@link 
XercesProvider}, {@link WoodstoxProvider}, {@link SaxonProvider}.</li>
  *   <li>Third-party providers discovered via {@link ServiceLoader}, in the 
order {@link ServiceLoader} yields them.</li>
- *   <li>If nothing matches, {@link 
UnsupportedXmlImplementationException}.</li>
+ *   <li>If nothing matches, {@link HardeningException}.</li>
  * </ol>
  *
  * <p>Bundled providers are consulted first so that a third-party provider on 
the classpath cannot intercept hardening of a factory class this library already
@@ -76,7 +75,7 @@ public static ProviderRegistry getInstance() {
      *
      * @param factoryClass the concrete factory class; never {@code null}.
      * @return the matching provider.
-     * @throws UnsupportedXmlImplementationException if no provider matches.
+     * @throws HardeningException if no provider matches.
      */
     public XmlProvider providerFor(final Class<?> factoryClass) {
         Objects.requireNonNull(factoryClass);
@@ -94,7 +93,10 @@ private XmlProvider lookup(final Class<?> factoryClass) {
                 return provider;
             }
         }
-        throw new UnsupportedXmlImplementationException(factoryClass);
+        throw new HardeningException(String.format(
+                "No XmlProvider supports JAXP factory class %s. Add a 
supported JAXP implementation to the classpath, "
+                        + "or register a custom XmlProvider via 
ServiceLoader.",
+                factoryClass.getName()));
     }
 
     private static List<XmlProvider> bundledProviders() {
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index a7e7878..4fe6566 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -60,7 +60,7 @@ stylesheet) is blocked, and DOCTYPE input is rejected 
wherever the underlying im
 
 Out of the box the library recognises the stock JDK JAXP implementations, 
Apache Xerces 2.x, Woodstox, and Saxon-HE. If
 a factory resolves to an implementation not covered by any bundled or 
registered provider, every `XmlFactories` method
-throws `UnsupportedXmlImplementationException`.
+throws `IllegalStateException` with a message naming the unsupported class.
 
 Support for additional implementations can be plugged in by publishing an
 `org.apache.commons.xml.factory.spi.XmlProvider` through the standard Java 
`ServiceLoader` mechanism. Bundled providers
diff --git 
a/src/test/java/org/apache/commons/xml/factory/UnsupportedXmlImplementationTest.java
 
b/src/test/java/org/apache/commons/xml/factory/UnsupportedXmlImplementationTest.java
index d83ef82..a22b0c2 100644
--- 
a/src/test/java/org/apache/commons/xml/factory/UnsupportedXmlImplementationTest.java
+++ 
b/src/test/java/org/apache/commons/xml/factory/UnsupportedXmlImplementationTest.java
@@ -16,10 +16,7 @@
  */
 package org.apache.commons.xml.factory;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -30,7 +27,7 @@
 import org.junit.jupiter.api.Test;
 
 /**
- * Verifies that an unknown factory class surfaces {@link 
UnsupportedXmlImplementationException} with the class attached.
+ * Verifies that an unknown factory class surfaces {@link 
IllegalStateException} with a message naming the class and pointing at the 
remediation path.
  */
 class UnsupportedXmlImplementationTest {
 
@@ -67,10 +64,9 @@ public boolean getFeature(final String name) {
 
     @Test
     void registryRejectsUnknownFactory() {
-        final UnsupportedXmlImplementationException thrown = assertThrows(
-                UnsupportedXmlImplementationException.class,
+        final IllegalStateException thrown = assertThrows(
+                IllegalStateException.class,
                 () -> 
ProviderRegistry.getInstance().providerFor(FakeDocumentBuilderFactory.class));
-        assertSame(FakeDocumentBuilderFactory.class, 
thrown.getUnsupportedFactoryClass());
         assertNotNull(thrown.getMessage());
         
assertTrue(thrown.getMessage().contains(FakeDocumentBuilderFactory.class.getName()),
                 "Exception message must name the unsupported class: " + 
thrown.getMessage());
diff --git 
a/src/test/java/org/apache/commons/xml/factory/internal/ProviderRegistryTest.java
 
b/src/test/java/org/apache/commons/xml/factory/internal/ProviderRegistryTest.java
index 684ad8f..318e627 100644
--- 
a/src/test/java/org/apache/commons/xml/factory/internal/ProviderRegistryTest.java
+++ 
b/src/test/java/org/apache/commons/xml/factory/internal/ProviderRegistryTest.java
@@ -18,11 +18,11 @@
 
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.Arrays;
 import java.util.Collections;
 
-import org.apache.commons.xml.factory.UnsupportedXmlImplementationException;
 import org.apache.commons.xml.factory.spi.XmlProvider;
 import org.junit.jupiter.api.Test;
 
@@ -57,12 +57,13 @@ void providerForNullThrowsNpe() {
     }
 
     @Test
-    void providerForUnknownClassThrowsUnsupportedWithClassAttached() {
+    void providerForUnknownClassThrowsHardeningException() {
         final ProviderRegistry registry = new 
ProviderRegistry(Collections.emptyList());
-        final UnsupportedXmlImplementationException thrown = assertThrows(
-                UnsupportedXmlImplementationException.class,
+        final HardeningException thrown = assertThrows(
+                HardeningException.class,
                 () -> registry.providerFor(String.class));
-        assertSame(String.class, thrown.getUnsupportedFactoryClass());
+        assertTrue(thrown.getMessage().contains(String.class.getName()),
+                "Exception message must name the unsupported class: " + 
thrown.getMessage());
     }
 
     @Test
@@ -94,7 +95,7 @@ void nonMatchingBundledProviderFallsThroughToNext() {
     @Test
     void emptyBundledListWithNoServiceLoaderProvidersThrows() {
         final ProviderRegistry registry = new 
ProviderRegistry(Collections.emptyList());
-        assertThrows(UnsupportedXmlImplementationException.class,
+        assertThrows(HardeningException.class,
                 () -> registry.providerFor(Integer.class));
     }
 }

Reply via email to