I use jaxb for unmarshalling, but when I use a ForkJoinPool execute() method, I get a "java.log.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory", but I'm sure of the presence in the classpath in my runtime, because when I don't use a ForkJoinPool it work properly ... do you know a problem or workaround for that ?
I use Java 11
my code:
ForkJoinPool commonPool = ForkJoinPool.commonPool();
commonPool.execute(() -> {
try {
String messageFileContent = Files.readString(Paths.get(
this.getClass().getClassLoader().getResource("xml-to-process.xml").getPath()));
JAXBContext jaxbContext = JAXBContext.newInstance(ObjectFactory.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
// avoiding schema validation for more performance
jaxbUnmarshaller.setSchema(null);
UpdateWorkOrder updateWorkOrder = (UpdateWorkOrder) jaxbUnmarshaller.unmarshal(new StringReader(messageFileContent));
} catch (Exception e) {
e.printStackTrace();
}
});
it's very strange no ... ? Outside the execute() of ForkJoinPool, the parsing was correclty performed.
The error is:
javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
with linked exception:
[java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory]
java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(Unknown Source)
at java.base/java.util.concurrent.ForkJoinTask.doExec(Unknown Source)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(Unknown Source)
at java.base/java.util.concurrent.ForkJoinPool.scan(Unknown Source)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(Unknown Source)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
at javax.xml.bind.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.java:92)
at javax.xml.bind.ServiceLoaderUtil.safeLoadClass(ServiceLoaderUtil.java:125)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:230)
While NightShade's answer completely describes the problem, let me add some details.
The Servlet API world and the concurrent world are quite incompatible: the former assumes that all computation is done on the same thread (ServletRequest#startAsync is a relatively recent addition). Therefore applications and libraries using the Servlet API often attach objects to the current Thread, e.g.:
RequestContextHolder to the current thread (as ThreadLocal),CurrentInstance,This means that whenever you want to execute something on another thread, you need to copy all these objects onto the destination thread. An easy way to do it is to write a wrapper for your Runnable's (and Callable<T>s), which sets up the environment before starting the execution:
public class WrappedRunnable implements Runnable {
private final ClassLoader ccl;
... // other objects
private final Runnable runnable;
public static Runnable wrap(final Runnable runnable) {
if (runnable instanceof WrappedRunnable) {
return runnable;
}
return new WrappedRunnable(runnable);
}
public WrappedRunnable(final Runnable runnable) {
this.ccl = Thread.currentThread().getContextClassLoader();
... // other objects
this.runnable = runnable;
}
@Override
public void run() {
final ClassLoader oldCcl = Thread.currentThread().getContextClassLoader();
... // save the value of other objects
try {
Thread.currentThread().setContextClassLoader(ccl);
... // set the value of other objects
runnable.run();
} finally {
Thread.currentThread().setContextClassLoader(oldCcl);
// restore the value of other objects
}
}
}
You can also write your own ExecutorService (you are actually using the ForkJoinPool as ExecutorService) or ForkJoinPool, which will wrap the Runnables automatically.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With