Skip to content

Add the JAXP static factory methods to the hardened factory classes - #57

Merged
garydgregory merged 6 commits into
mainfrom
feature/jaxp-factory-methods
Aug 28, 2026
Merged

Add the JAXP static factory methods to the hardened factory classes#57
garydgregory merged 6 commits into
mainfrom
feature/jaxp-factory-methods

Conversation

@ppkarwasz

Copy link
Copy Markdown
Member

Warning

Stacked on #56.

Mirror on each Hardening*Factory the static factory methods its JAXP counterpart offers, so the hardened classes are a drop-in replacement at every construction site:

  • JDK 8: the factoryClassName/ClassLoader overloads, the SchemaFactory and XPathFactory language/object-model variants, and the StAX newFactory family (omitting only the deprecated XMLInputFactory.newInstance(String, ClassLoader)).
  • Java 9 newDefaultInstance(): resolved through a MethodHandle at runtime, falling back to instantiating the JDK's built-in implementation by class name on Java 8. This way we backport the newDefaultInstance() to Java 8. Calling the new methods on Java 9+ is necessary, because the classes are not exported through JPMS.
  • Java 13 newNSInstance() family: implemented the way the JDK does — namespace awareness enabled on the non-NS counterpart through a private makeNSAware helper. Calling the Java 13 methods directly is not necessary: they are mere decorators.

The internal namespace-aware parser construction (newHardenedReader, hardenSourceToDom, HardeningXPath.parse) now reuses newNSInstance() instead of hand-rolling the same recipe.

I bumped the Android requirement to API 26 (2017), since previous versions don't handle MethodHandle.invokeExact().

🤖 Generated with Claude Code

@ppkarwasz

Copy link
Copy Markdown
Member Author

This PR includes the same changes to the Animal Sniffer plugin that apache/commons-parent#719.

I included it here, so we can run the checks without making a new parent release. If other problems arise before commons-xml is ready, we can fix those in the same parent release as well.

Base automatically changed from feature/merge-hardeners-into-factories to main August 28, 2026 10:51
Mirror on each Hardening*Factory the static factory methods its JAXP
counterpart offers in JDK 8, omitting only the deprecated
XMLInputFactory.newInstance(String, ClassLoader): the explicit
factoryClassName/ClassLoader overloads, the SchemaFactory and
XPathFactory language/object-model variants, and the StAX newFactory
family. Each is a one-liner through the class's hardening recipe.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WWJ4LAxx3TX5RwNvwKbAS3
Each factory class gains newDefaultInstance (newDefaultFactory for StAX)
without raising the compile baseline: the Java 9 JAXP method is resolved
through MethodHandles.publicLookup() and invoked when present; on Java 8
the JDK's built-in implementation is instantiated by class name instead.
Where the platform provides neither, for example Android, the lookup
miss surfaces as the factory's own configuration error, like any
newInstance miss. java.lang.invoke raises the supported Android baseline
to API level 26, and the bnd instructions drop the JDK-internal package
inferred from the reflective StAX fallback.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WWJ4LAxx3TX5RwNvwKbAS3
DocumentBuilderFactory and SAXParserFactory gain the newNSInstance,
newNSInstance(String, ClassLoader) and newDefaultNSInstance mirrors,
resolved through MethodHandles.publicLookup() like the Java 9 methods.
Where the platform predates them, the fallback enables namespace
awareness on the corresponding newInstance lookup, the behavior the
JAXP methods are specified to have, so the non-default variants work on
every supported platform including Android; newDefaultNSInstance
inherits the newDefaultInstance fallback chain.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WWJ4LAxx3TX5RwNvwKbAS3
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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ErRKq7RUeQ9LGrSboSUyYm
…niffer

javac records the ad-hoc call-site descriptor for invokeExact, which no
signature database lists, so the JDK 8 check flags a false positive on
every MethodHandle lookup call site.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ErRKq7RUeQ9LGrSboSUyYm
Describe on the site and in the package Javadoc the static factory
methods mirrored from JAXP (the JDK 8 overloads, Java 9
newDefaultInstance and Java 13 newNSInstance families), all usable on
Java 8, with newDefaultInstance as an opt-out of JAXP pluggability.

Assisted-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ErRKq7RUeQ9LGrSboSUyYm
@garydgregory
garydgregory force-pushed the feature/jaxp-factory-methods branch from 64c1c91 to a45add7 Compare August 28, 2026 10:51
@garydgregory
garydgregory merged commit c17ea48 into main Aug 28, 2026
18 checks passed
@garydgregory
garydgregory deleted the feature/jaxp-factory-methods branch August 28, 2026 11:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants