在ForkJoinPool Java中找不到JAXB类 [英] JAXB class not found with ForkJoinPool Java

查看:113
本文介绍了在ForkJoinPool Java中找不到JAXB类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用jaxb进行编组,但是当我使用ForkJoinPool execute()方法时,出现了"java.log.ClassNotFoundException:com.sun.xml.internal.bind.v2.ContextFactory",但是我确定我的运行时类路径中是否存在该类,因为当我不使用ForkJoinPool时,它可以正常工作...您知道该问题还是解决方法吗?

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 ?

我使用Java 11

I use Java 11

我的代码:

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();
            }
        });

这很奇怪,不是吗?在ForkJoinPool的execute()外部,解析是正确执行的.

it's very strange no ... ? Outside the execute() of ForkJoinPool, the parsing was correclty performed.

错误是:

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)

推荐答案

虽然NightShade的答案完全描述了问题,但让我添加一些细节.

While NightShade's answer completely describes the problem, let me add some details.

Servlet API世界和并发世界是完全不兼容的:前者假定所有计算都在同一线程上完成( ServletRequest#startAsync 是相对较新的功能).因此,使用Servlet API的应用程序和库通常会将对象附加到当前的 Thread 上,例如:

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.:

  • 执行请求的线程将应用程序的类加载器附加为"context classloader"
  • Spring将 RequestContextHolder 附加到当前线程(作为 ThreadLocal ),
  • Vaadin通过 CurrentInstance
  • 附加许多对象
  • ...
  • the thread executing the request has the application's classloader attached as "context classloader",
  • Spring attaches a RequestContextHolder to the current thread (as ThreadLocal),
  • Vaadin attaches many objects through CurrentInstance,
  • ...

这意味着每当您想在另一个线程上执行某些操作时,都需要将所有这些对象复制到目标线程上.一种简单的方法是为您的 Runnable (和 Callable< T> s)编写一个包装器,该包装器将在开始执行之前设置环境:

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
      }
   }
}

您还可以编写自己的 ExecutorService (您实际上是将 ForkJoinPool 用作 ExecutorService )或

You can also write your own ExecutorService (you are actually using the ForkJoinPool as ExecutorService) or ForkJoinPool, which will wrap the Runnables automatically.

这篇关于在ForkJoinPool Java中找不到JAXB类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆