Hi yes, thanks for mentioning this.
In the context of API specifications, "immutable" often means that from the point of
view of the public API, the state of the object cannot be observed to mutate. And
yes it usually implies thread safety. Of course that's possible to achieve if none
of the object's fields are mutated, but it's possible for such an object to have
mutable fields. (String and BigInteger are examples of this.)
Unfortunately the CatalogImpl object is mutated to hold temporary state that's used
during the resolution process. This temporary state doesn't really belong in the
object itself, so it seems likely that a fix would involve refactoring this
temporary state out of the Catalog itself into an object owned by some resolver
object (or similar).
We'll take another look at the docs here to see if other updates are necessary.
s'marks
On 10/22/25 11:26 AM, Elliot Barlas wrote:
Thanks, Stuart.
Regarding specification, I noticed that the javax.xml.catalog package summary[1]
indicates that "A Catalog object is immutable." Immutable typically indicates that
internal state cannot be changed and it implies thread-safety. It might be worth
clarifying the javadocs.
[1]
https://docs.oracle.com/en/java/javase/25/docs/api/java.xml/javax/xml/catalog/package-summary.html
On Tue, Oct 21, 2025 at 8:51 PM Stuart Marks <[email protected]> wrote:
Hi Elliot,
Yes, this is indeed a bug. It seems that most of the XML and JAXP APIs
aren't
thread-safe and so must be used in a thread-confined manner. (Hm, I can't
seem to
find anything in the specifications about this... another thing to look
at.) Most
JAXP objects are constructed on demand. However, as you point out they end
up
using
a shared CatalogImpl instance that represents the built-in JDK catalog.
Since
catalog resolution mutates this object, it's a thread-safety issue.
I've filed
https://bugs.openjdk.org/browse/JDK-8370379
to cover this issue. Thanks for reporting it!
s'marks
On 10/14/25 3:07 PM, Elliot Barlas wrote:
> Hello core-libs-dev!
>
> There appears to be a thread-safety bug in
> com.sun.org.apache.xerces.internal.impl.XMLEntityManager related to the
> introduction of the following field[1] in the following commit[2].
>
> [1] CatalogResolver fDefCR // the default JDK Catalog Resolver
>
> [2]
https://github.com/openjdk/jdk/commit/93bdc2a6db91a95d6ee52ec92080e586c694dad5
<https://urldefense.com/v3/__https://github.com/openjdk/jdk/commit/93bdc2a6db91a95d6ee52ec92080e586c694dad5__;!!ACWV5N9M2RV99hQ!PKgSj2SeuOr4MCd4_Gx6yYDTmkSwn_53v3toPNh3ULqgJTW8B-suL5Rj6p6AR4cKJLpmLTdheaA8UfTNna9xkM3nOhEn$>
>
> Multiple threads executing the following sample code use the same
underlying
> javax.xml.catalog.CatalogImpl obtained from
> JdkXmlConfig.getInstance().getJdkCatalog(). CatalogImpl is not thread
safe. The
> resolveEntity method mutates the underlying JDK catalog[3].
>
> [3]
>
https://github.com/openjdk/jdk/blob/master/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java#L279
<https://urldefense.com/v3/__https://github.com/openjdk/jdk/blob/master/src/java.xml/share/classes/javax/xml/catalog/CatalogImpl.java*L279__;Iw!!ACWV5N9M2RV99hQ!PKgSj2SeuOr4MCd4_Gx6yYDTmkSwn_53v3toPNh3ULqgJTW8B-suL5Rj6p6AR4cKJLpmLTdheaA8UfTNna9xkHxYgLPG$>
>
> XMLEntityManager entityManager = new XMLEntityManager();
> XMLResourceIdentifier resourceIdentifier = new XMLResourceIdentifierImpl(
> "http://example.com/dtd/sample.dtd
<https://urldefense.com/v3/__http://example.com/dtd/sample.dtd__;!!ACWV5N9M2RV99hQ!PKgSj2SeuOr4MCd4_Gx6yYDTmkSwn_53v3toPNh3ULqgJTW8B-suL5Rj6p6AR4cKJLpmLTdheaA8UfTNna9xkAFCYHAv$>",
> "sample.dtd",
> "http://example.com/base/
<https://urldefense.com/v3/__http://example.com/base/__;!!ACWV5N9M2RV99hQ!PKgSj2SeuOr4MCd4_Gx6yYDTmkSwn_53v3toPNh3ULqgJTW8B-suL5Rj6p6AR4cKJLpmLTdheaA8UfTNna9xkDeCD3yJ$>",
> "http://example.com/base/sample.dtd
<https://urldefense.com/v3/__http://example.com/base/sample.dtd__;!!ACWV5N9M2RV99hQ!PKgSj2SeuOr4MCd4_Gx6yYDTmkSwn_53v3toPNh3ULqgJTW8B-suL5Rj6p6AR4cKJLpmLTdheaA8UfTNna9xkA6PDux_$>");
> entityManager.resolveEntity(resourceIdentifier);
>
> Prior to the commit above, this code did not access a shared JDK
CatalogImpl.
>
> -Elliot Barlas