Skip to content

Commit baf27bd

Browse files
SAY-5MaximPlusov
authored andcommitted
fix: self-initialise XMP container thread-locals to avoid NPE on foreign threads
Signed-off-by: Sai Asish Y <say.apm35@gmail.com>
1 parent cb8e9d7 commit baf27bd

2 files changed

Lines changed: 57 additions & 2 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* This file is part of veraPDF Library core, a module of the veraPDF project.
3+
* Copyright (c) 2015-2026, veraPDF Consortium <info@verapdf.org>
4+
* All rights reserved.
5+
*
6+
* veraPDF Library core is free software: you can redistribute it and/or modify
7+
* it under the terms of either:
8+
*
9+
* The GNU General public license GPLv3+.
10+
* You should have received a copy of the GNU General Public License
11+
* along with veraPDF Library core as the LICENSE.GPL file in the root of the source
12+
* tree. If not, see http://www.gnu.org/licenses/ or
13+
* https://www.gnu.org/licenses/gpl-3.0.en.html.
14+
*
15+
* The Mozilla Public License MPLv2+.
16+
* You should have received a copy of the Mozilla Public License along with
17+
* veraPDF Library core as the LICENSE.MPL file in the root of the source tree.
18+
* If a copy of the MPL was not distributed with this file, you can obtain one at
19+
* http://mozilla.org/MPL/2.0/.
20+
*/
21+
package org.verapdf.model.impl.axl;
22+
23+
import static org.junit.Assert.assertEquals;
24+
25+
import java.util.concurrent.atomic.AtomicReference;
26+
27+
import org.junit.Test;
28+
import org.verapdf.xmp.XMPConst;
29+
import org.verapdf.xmp.XMPMetaFactory;
30+
31+
public class XMPSchemaRegistryThreadTest {
32+
33+
@Test
34+
public void getNamespacePrefixFromForeignThread() throws InterruptedException {
35+
// The singleton registry is constructed on this thread, which seeds the
36+
// per-thread containers only here. Another thread (such as a virtual
37+
// thread) has its own empty container slots.
38+
XMPMetaFactory.getSchemaRegistry();
39+
40+
AtomicReference<String> prefix = new AtomicReference<>();
41+
AtomicReference<Throwable> failure = new AtomicReference<>();
42+
Thread worker = new Thread(() -> {
43+
try {
44+
prefix.set(XMPMetaFactory.getSchemaRegistry().getNamespacePrefix(XMPConst.NS_RDF));
45+
} catch (Throwable t) {
46+
failure.set(t);
47+
}
48+
});
49+
worker.start();
50+
worker.join();
51+
52+
assertEquals(null, failure.get());
53+
assertEquals("rdf:", prefix.get());
54+
}
55+
}

xmp-core/src/main/java/org/verapdf/xmp/containers/StaticXmpCoreContainers.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ public class StaticXmpCoreContainers {
88
/**
99
* a map from a namespace URI to its registered prefix
1010
*/
11-
private static final ThreadLocal<Map<String, String>> namespaceToPrefixMap = new ThreadLocal<>();
11+
private static final ThreadLocal<Map<String, String>> namespaceToPrefixMap = ThreadLocal.withInitial(HashMap::new);
1212

1313
/**
1414
* a map from a prefix to the associated namespace URI
1515
*/
16-
private static final ThreadLocal<Map<String, String>> prefixToNamespaceMap = new ThreadLocal<>();
16+
private static final ThreadLocal<Map<String, String>> prefixToNamespaceMap = ThreadLocal.withInitial(HashMap::new);
1717

1818
/**
1919
* Clears all namespaces and prefixes.

0 commit comments

Comments
 (0)