This is an automated email from the ASF dual-hosted git repository. ppkarwasz pushed a commit to branch feature/reduce-shade-footprint in repository https://gitbox.apache.org/repos/asf/commons-xml.git
commit a442d1cfd54c969d70150eecebd16c9b63347e2d Author: Piotr P. Karwasz <[email protected]> AuthorDate: Wed Jul 8 10:29:43 2026 +0200 Inline the typed JAXP setters into each hardener Move the setFeature/setOptionalFeature/trySetProperty/trySetAttribute/ setOptionalAttribute helpers out of the shared JaxpSetters class and into the hardener that uses them, as private methods, so shading one hardener no longer drags in the setters (and dead overloads) of the others. Only the shared "Failed to set ..." message stays central, on HardeningException.settingFailed. Delete JaxpSetters. Cuts the DOM/SAX/StAX shade closures by the whole JaxpSetters class (7946 bytes): DocumentBuilderHardener 26225 -> 19265, SAXParserHardener 32508 -> 25721, StaxHardener 28173 -> 20547 bytes. Update ShadingFootprintTest's expected sets accordingly. Assisted-By: Claude Opus 4.8 <[email protected]> --- .../commons/xml/DocumentBuilderHardener.java | 19 ++- .../java/org/apache/commons/xml/JaxpSetters.java | 151 --------------------- .../org/apache/commons/xml/SAXParserHardener.java | 37 ++++- .../java/org/apache/commons/xml/StaxHardener.java | 14 +- .../apache/commons/xml/TransformerHardener.java | 10 +- .../java/org/apache/commons/xml/XPathHardener.java | 19 ++- .../apache/commons/xml/ShadingFootprintTest.java | 7 +- 7 files changed, 85 insertions(+), 172 deletions(-) diff --git a/src/main/java/org/apache/commons/xml/DocumentBuilderHardener.java b/src/main/java/org/apache/commons/xml/DocumentBuilderHardener.java index 28150cb..a97af17 100644 --- a/src/main/java/org/apache/commons/xml/DocumentBuilderHardener.java +++ b/src/main/java/org/apache/commons/xml/DocumentBuilderHardener.java @@ -17,9 +17,6 @@ package org.apache.commons.xml; -import static org.apache.commons.xml.JaxpSetters.setFeature; -import static org.apache.commons.xml.JaxpSetters.setOptionalFeature; - import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -66,6 +63,22 @@ static DocumentBuilderFactory harden(final DocumentBuilderFactory factory) { return new HardeningDocumentBuilderFactory(factory); } + private static void setFeature(final DocumentBuilderFactory factory, final String feature, final boolean value) { + try { + factory.setFeature(feature, value); + } catch (final Exception e) { + throw HardeningException.settingFailed("feature", feature, factory, e); + } + } + + private static void setOptionalFeature(final DocumentBuilderFactory factory, final String feature, final boolean value) { + try { + factory.setFeature(feature, value); + } catch (final Exception e) { + // Ignored: the implementation does not recognize this feature. + } + } + private DocumentBuilderHardener() { } } diff --git a/src/main/java/org/apache/commons/xml/JaxpSetters.java b/src/main/java/org/apache/commons/xml/JaxpSetters.java deleted file mode 100644 index 471a3a2..0000000 --- a/src/main/java/org/apache/commons/xml/JaxpSetters.java +++ /dev/null @@ -1,151 +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; - -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.SAXParserFactory; -import javax.xml.stream.XMLInputFactory; -import javax.xml.transform.TransformerFactory; -import javax.xml.validation.SchemaFactory; -import javax.xml.validation.Validator; -import javax.xml.validation.ValidatorHandler; -import javax.xml.xpath.XPathFactory; - -import org.xml.sax.XMLReader; - -/** - * Setter helpers shared by the bundled hardening providers. - * - * <p>Each overload wraps a single JAXP setter (feature, attribute or property) in a try/catch that translates any thrown exception into a - * {@link HardeningException} whose message names the offending feature, attribute or property and the concrete factory class.</p> - */ -final class JaxpSetters { - - /** Action that may throw any exception; used to share a single try/catch around every JAXP setter. */ - @FunctionalInterface - private interface ThrowingAction { - void run() throws Exception; - } - - private static final String KIND_FEATURE = "feature"; - - private static void apply(final Object factory, final String kind, final String name, final ThrowingAction action) { - try { - action.run(); - } catch (final Exception e) { - throw HardeningException.settingFailed(kind, name, factory, e); - } - } - - static void setFeature(final DocumentBuilderFactory factory, final String feature, final boolean value) { - apply(factory, KIND_FEATURE, feature, () -> factory.setFeature(feature, value)); - } - - static void setFeature(final SAXParserFactory factory, final String feature, final boolean value) { - apply(factory, KIND_FEATURE, feature, () -> factory.setFeature(feature, value)); - } - - static void setFeature(final TransformerFactory factory, final String feature, final boolean value) { - apply(factory, KIND_FEATURE, feature, () -> factory.setFeature(feature, value)); - } - - static void setFeature(final XPathFactory factory, final String feature, final boolean value) { - apply(factory, KIND_FEATURE, feature, () -> factory.setFeature(feature, value)); - } - - static void setFeature(final SchemaFactory factory, final String feature, final boolean value) { - apply(factory, KIND_FEATURE, feature, () -> factory.setFeature(feature, value)); - } - - static void setFeature(final Validator validator, final String feature, final boolean value) { - apply(validator, KIND_FEATURE, feature, () -> validator.setFeature(feature, value)); - } - - static void setFeature(final ValidatorHandler handler, final String feature, final boolean value) { - apply(handler, KIND_FEATURE, feature, () -> handler.setFeature(feature, value)); - } - - static void setFeature(final XMLReader reader, final String feature, final boolean value) { - apply(reader, KIND_FEATURE, feature, () -> reader.setFeature(feature, value)); - } - - static void setOptionalFeature(final DocumentBuilderFactory factory, final String feature, final boolean value) { - try { - factory.setFeature(feature, value); - } catch (final Exception e) { - // Ignored: the implementation does not recognize this feature. - } - } - - static void setOptionalFeature(final XMLReader reader, final String feature, final boolean value) { - try { - reader.setFeature(feature, value); - } catch (final Exception e) { - // Ignored: the implementation does not recognize this feature. - } - } - - static void setOptionalFeature(final XPathFactory factory, final String feature, final boolean value) { - try { - factory.setFeature(feature, value); - } catch (final Exception e) { - // Ignored: the implementation does not recognize this feature. - } - } - - static void setOptionalProperty(final XMLInputFactory factory, final String property, final Object value) { - trySetProperty(factory, property, value); - } - - /** - * Sets a property on an {@link XMLReader} and returns whether the implementation accepted it. - * - * @param reader The target reader on which to set the property. - * @param property The name of the property to set. - * @param value The value of the property to set. - * @return {@code true} if the property was applied, {@code false} if the implementation rejected it. - */ - static boolean trySetProperty(final XMLReader reader, final String property, final Object value) { - try { - reader.setProperty(property, value); - return true; - } catch (final Exception e) { - return false; - } - } - - /** - * Sets a property on an {@link XMLInputFactory} and returns whether the implementation accepted it. - * - * @param factory The target factory on which to set the property. - * @param property The name of the property to set. - * @param value The value of the property to set. - * @return {@code true} if the property was applied, {@code false} if the implementation rejected it. - */ - static boolean trySetProperty(final XMLInputFactory factory, final String property, final Object value) { - try { - factory.setProperty(property, value); - return true; - } catch (final Exception e) { - return false; - } - } - - private JaxpSetters() { - } -} diff --git a/src/main/java/org/apache/commons/xml/SAXParserHardener.java b/src/main/java/org/apache/commons/xml/SAXParserHardener.java index 5a9862a..5e0d67c 100644 --- a/src/main/java/org/apache/commons/xml/SAXParserHardener.java +++ b/src/main/java/org/apache/commons/xml/SAXParserHardener.java @@ -17,10 +17,6 @@ package org.apache.commons.xml; -import static org.apache.commons.xml.JaxpSetters.setFeature; -import static org.apache.commons.xml.JaxpSetters.setOptionalFeature; -import static org.apache.commons.xml.JaxpSetters.trySetProperty; - import java.io.IOException; import java.util.Objects; @@ -180,6 +176,39 @@ static XMLReader hardenReader(final XMLReader reader) { return new HardeningXMLReader(reader); } + private static void setFeature(final SAXParserFactory factory, final String feature, final boolean value) { + try { + factory.setFeature(feature, value); + } catch (final Exception e) { + throw HardeningException.settingFailed("feature", feature, factory, e); + } + } + + private static void setFeature(final XMLReader reader, final String feature, final boolean value) { + try { + reader.setFeature(feature, value); + } catch (final Exception e) { + throw HardeningException.settingFailed("feature", feature, reader, e); + } + } + + private static void setOptionalFeature(final XMLReader reader, final String feature, final boolean value) { + try { + reader.setFeature(feature, value); + } catch (final Exception e) { + // Ignored: the implementation does not recognize this feature. + } + } + + private static boolean trySetProperty(final XMLReader reader, final String property, final Object value) { + try { + reader.setProperty(property, value); + return true; + } catch (final Exception e) { + return false; + } + } + private SAXParserHardener() { } } diff --git a/src/main/java/org/apache/commons/xml/StaxHardener.java b/src/main/java/org/apache/commons/xml/StaxHardener.java index 6247fdd..128b44a 100644 --- a/src/main/java/org/apache/commons/xml/StaxHardener.java +++ b/src/main/java/org/apache/commons/xml/StaxHardener.java @@ -17,9 +17,6 @@ package org.apache.commons.xml; -import static org.apache.commons.xml.JaxpSetters.setOptionalProperty; -import static org.apache.commons.xml.JaxpSetters.trySetProperty; - import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; @@ -81,7 +78,7 @@ protected Object onUnresolved(final String publicID, final String systemID, fina static XMLInputFactory harden(final XMLInputFactory factory) { // Optional: Zephyr's StAX equivalent of XERCES_LOAD_EXTERNAL_DTD=false skips the external DTD subset entirely. - setOptionalProperty(factory, ZEPHYR_IGNORE_EXTERNAL_DTD, true); + trySetProperty(factory, ZEPHYR_IGNORE_EXTERNAL_DTD, true); // Each hook carries its own FallbackDenyXMLResolver floor; a caller can opt specific entities in through it, but cannot remove it (see // HardeningXMLInputFactory, which routes a caller-set resolver into the floor rather than replacing it). The DTD-subset and undeclared-entity hooks skip @@ -95,6 +92,15 @@ && trySetProperty(factory, WSTX_UNDECLARED_ENTITY_RESOLVER, new Resolvers.Fallba return new HardeningXMLInputFactory(factory); } + private static boolean trySetProperty(final XMLInputFactory factory, final String property, final Object value) { + try { + factory.setProperty(property, value); + return true; + } catch (final Exception e) { + return false; + } + } + private StaxHardener() { } } diff --git a/src/main/java/org/apache/commons/xml/TransformerHardener.java b/src/main/java/org/apache/commons/xml/TransformerHardener.java index f289363..b0d1b30 100644 --- a/src/main/java/org/apache/commons/xml/TransformerHardener.java +++ b/src/main/java/org/apache/commons/xml/TransformerHardener.java @@ -17,8 +17,6 @@ package org.apache.commons.xml; -import static org.apache.commons.xml.JaxpSetters.setFeature; - import java.util.Arrays; import java.util.Collections; import java.util.HashSet; @@ -75,6 +73,14 @@ static TransformerFactory harden(final TransformerFactory factory) { return new HardeningTransformerFactory((SAXTransformerFactory) factory); } + private static void setFeature(final TransformerFactory factory, final String feature, final boolean value) { + try { + factory.setFeature(feature, value); + } catch (final Exception e) { + throw HardeningException.settingFailed("feature", feature, factory, e); + } + } + private TransformerHardener() { } } diff --git a/src/main/java/org/apache/commons/xml/XPathHardener.java b/src/main/java/org/apache/commons/xml/XPathHardener.java index 38f3e9d..4a995cd 100644 --- a/src/main/java/org/apache/commons/xml/XPathHardener.java +++ b/src/main/java/org/apache/commons/xml/XPathHardener.java @@ -17,9 +17,6 @@ package org.apache.commons.xml; -import static org.apache.commons.xml.JaxpSetters.setFeature; -import static org.apache.commons.xml.JaxpSetters.setOptionalFeature; - import java.util.Arrays; import java.util.Collections; import java.util.HashSet; @@ -73,6 +70,22 @@ static XPathFactory harden(final XPathFactory factory) { return factory; } + private static void setFeature(final XPathFactory factory, final String feature, final boolean value) { + try { + factory.setFeature(feature, value); + } catch (final Exception e) { + throw HardeningException.settingFailed("feature", feature, factory, e); + } + } + + private static void setOptionalFeature(final XPathFactory factory, final String feature, final boolean value) { + try { + factory.setFeature(feature, value); + } catch (final Exception e) { + // Ignored: the implementation does not recognize this feature. + } + } + private XPathHardener() { } } diff --git a/src/test/java/org/apache/commons/xml/ShadingFootprintTest.java b/src/test/java/org/apache/commons/xml/ShadingFootprintTest.java index 08348ec..237d93e 100644 --- a/src/test/java/org/apache/commons/xml/ShadingFootprintTest.java +++ b/src/test/java/org/apache/commons/xml/ShadingFootprintTest.java @@ -40,7 +40,7 @@ * * <p>Using {@code jdependency}, the same library {@code maven-shade-plugin}'s {@code minimizeJar} uses, this test computes each entry point's transitive class * closure over the compiled {@code target/classes} and pins it to an expected set. It keeps the DOM, SAX and StAX hardeners from silently regaining a dependency - * on classes they should not need (for example the shared {@code JaxpSetters} or the sibling resolver floors), and records that the TrAX, XPath and schema entry + * on classes they should not need (for example the sibling resolver floors, or another hardener), and records that the TrAX, XPath and schema entry * points still pull the whole library through the {@link XmlFactories} re-hardening cycle. Update the expected sets deliberately: a change here is a change to what * a downstream shade includes.</p> */ @@ -53,25 +53,22 @@ class ShadingFootprintTest { private static final Set<String> DOCUMENT_BUILDER_HARDENER = set( "DocumentBuilderHardener", "HardeningDocumentBuilder", "HardeningDocumentBuilderFactory", CORE, - "JaxpSetters", "JaxpSetters$ThrowingAction", "Resolvers", "Resolvers$FallbackDenyResolver", "Resolvers$FallbackDenyLSResourceResolver", "Resolvers$FallbackDenyURIResolver", "Resolvers$FallbackDenyXMLResolver", "Resolvers$FallbackIgnoreXMLResolver"); private static final Set<String> SAX_PARSER_HARDENER = set( "SAXParserHardener", "SAXParserHardener$DtdAwareDenyResolver", "SAXParserHardener$HardeningExpatXMLReader", "HardeningSAXParser", "HardeningSAXParserFactory", "HardeningXMLReader", CORE, - "JaxpSetters", "JaxpSetters$ThrowingAction", "Resolvers", "Resolvers$FallbackDenyResolver", "Resolvers$FallbackDenyLSResourceResolver", "Resolvers$FallbackDenyURIResolver", "Resolvers$FallbackDenyXMLResolver", "Resolvers$FallbackIgnoreXMLResolver"); private static final Set<String> STAX_HARDENER = set( "StaxHardener", "StaxHardener$DtdSubsetFloor", "HardeningXMLInputFactory", CORE, - "JaxpSetters", "JaxpSetters$ThrowingAction", "Resolvers", "Resolvers$FallbackDenyResolver", "Resolvers$FallbackDenyLSResourceResolver", "Resolvers$FallbackDenyURIResolver", "Resolvers$FallbackDenyXMLResolver", "Resolvers$FallbackIgnoreXMLResolver"); /** The TrAX/XPath/schema entry points all pull the whole library through {@link XmlFactories}; this is its class count (Phase 4 territory to reduce). */ - private static final int WHOLE_LIBRARY_SIZE = 35; + private static final int WHOLE_LIBRARY_SIZE = 33; /** Entry points reported by the {@link #reportFootprint()} diagnostic, most-focused first, ending with the whole library. */ private static final String[] REPORTED = {
