Repository navigation
Build and validate SIRI 2.1 on JDK 24+ despite the JDK built-in XML catalog - #39
Merged
Merged
Conversation
vpaturet
marked this pull request as ready for review
October 12, 2026 09:01
vpaturet
marked this pull request as draft
October 12, 2026 09:07
vpaturet
force-pushed
the
fix/jdk24-builtin-xml-catalog
branch
from
October 12, 2026 09:26
d3a99e9 to
57ed676
Compare
…XML catalog JDK 22 introduced a built-in XML catalog in java.xml (JDK-8306055), and JDK 24 added the W3C DTDs and XSDs to it (JDK-8344800). One of its rules is a suffix match that rewrites every schema location ending in "XMLSchema.xsd" to the JDK's own copy of the XML Schema schema-for-schemas. The SIRI 2.1 standard ships the W3C xml namespace schema as xml/2009/01/XMLSchema.xsd, so on JDK 24+ that file is shadowed and loading the schema fails with "Cannot resolve the name 'xml:lang'". The XSDs are part of the standard and are left untouched. Build: pass a user catalog (src/main/xjc/siri-2.1-catalog.xml) to XJC via the cxf-xjc-plugin catalog option, so the location resolves to the bundled file. Also bump maven-compiler-plugin to 3.16.0 with <release>11</release> and cxf-xjc-plugin to 4.2.0. Runtime: SiriValidator now sets a RelativeSchemaResourceResolver on the SchemaFactory that resolves schema imports relative to their base URI without consulting catalogs. The resolver returns an LSInput that carries only the resolved system id; Xerces opens the stream itself, only for the documents it has not already traversed, so nothing is leaked for schemas that are included or imported more than once. Xerces skips its accessExternalSchema check for locations a resource resolver has resolved, so the resolver only resolves file: and jar: locations, which keeps it inside the bundled schema tree, and leaves anything else to Xerces' own access check and catalog. It keeps the deprecated URL(URL, String) constructor on purpose: jar: URIs are opaque, so URI.resolve() cannot resolve relative references against them. SiriValidator previously rebuilt the whole SIRI schema set on every validate() call. Schema is immutable and thread-safe, so one compiled Schema per version is now built lazily via ConcurrentHashMap.computeIfAbsent and reused, as already done for the JAXB contexts. Cache hits take no lock, and a failed build is not cached so a later call retries. Verified with mvn clean install on JDK 25 and JDK 11, and by validating SIRI 2.0 and 2.1 documents on JDK 25 with schemas loaded from inside the OTP shaded jar.
vpaturet
force-pushed
the
fix/jdk24-builtin-xml-catalog
branch
from
October 12, 2026 10:04
57ed676 to
a5e8992
Compare
vpaturet
marked this pull request as ready for review
October 12, 2026 10:06
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The project does not build on JDK 24 or newer, and
SiriValidatorcannot validate SIRI 2.1 documents on those JDKs either.JDK 22 introduced a built-in XML catalog in
java.xml(JDK-8306055), and JDK 24 added the W3C DTDs and XSDs to it (JDK-8344800). One of its rules is a suffix match that rewrites every schema location ending inXMLSchema.xsdto the JDK's own copy of the XML Schema schema-for-schemas:The SIRI 2.1 standard ships the W3C xml-namespace schema as
xml/2009/01/XMLSchema.xsd, imported fromsiri_utility/siri_types.xsd. On JDK 24+ that file is shadowed,xml:langis no longer declared, and loading the schema fails:The XSDs are part of the standard and are left untouched. Upstream SIRI-CEN uses the same file name.
Changes
Build
pom.xml: pass a user catalog (src/main/xjc/siri-2.1-catalog.xml) to XJC through thecxf-xjc-plugincatalogoption for the SIRI 2.1 xsdOption. A user catalog takes precedence over the JDK built-in one, so the import resolves to the bundled file.maven-compiler-plugin3.8.0 → 3.16.0, using<release>11</release>instead of source/target. The bytecode target is unchanged.cxf-xjc-plugin4.0.0 → 4.2.0.Runtime
RelativeSchemaResourceResolver, set on theSchemaFactoryinSiriValidator. It resolves schema imports relative to their base URI (file or jar URLs) without consulting catalogs. Without it, SIRI 2.1 validation throws on JDK 24+ for consumers of the published jar. This affects the released 2.0.6 as well.LSInputthat carries only the resolved system id; it opens no stream itself. Xerces opens the document, and only if it has not already traversed it, so nothing is leaked for the many schemas that are included or imported more than once.accessExternalSchemacheck for any location a resource resolver has resolved: the resolver is the access policy. The resolver therefore only resolvesfile:andjar:locations, which keeps it inside the bundled schema tree, and returnsnullfor anything else so that Xerces applies its own access check and catalog. The bundled XSDs contain no absolute schema locations outside documentation text, so this path is never taken today.URL(URL, String)constructor on purpose:jar:URIs are opaque, soURI.resolve()returns the relative reference unchanged instead of resolving it. A comment in the code records this.SiriValidatorpreviously rebuilt the whole SIRI schema set (86 XSD files) on everyvalidate()call.Schemais immutable and thread-safe, so one compiledSchemaper version is now built lazily throughConcurrentHashMap.computeIfAbsentand reused, as already done for the JAXB contexts. Cache hits take no lock, and a failed build is not cached so a later call retries.Verification
mvn clean installon JDK 25mvn clean installon JDK 11otp-shaded-2.11.0-SNAPSHOT.jar, which bundles siri-java-model 2.0.6), with this PR's two validator classes placed ahead of the jarBefore the resolver change,
SiriXmlTestfailed on JDK 25 with the catalog error above, which is how the runtime problem was found. The bundled 2.0.6 fails the same way in the OTP jar run.Performance (schemas from the OTP jar, 200 timed calls after 50 warm-up calls, median per
validate()call)The first call still takes about 1.5 s to compile the schema set, now once per version per JVM instead of on every call. Open file descriptors stayed flat over the 250 validations in every configuration.
Notes
jdk.xml.jdkcatalog.resolvecannot be used as a workaround: it only governs what happens when the built-in catalog fails to resolve, and does not disable it. See the java.xml module summary, section "JDK built-in Catalog".