且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Eclipse/OSGI,Java 11,JAXB和类加载器

更新时间:2022-06-12 01:51:22

似乎我找到了解决方案.我的问题是必须出于两个不同的目的处理类加载器:

It seems I found a solution. My problem was having to deal with classloaders for two different purposes:

  1. JAXB用于实例化上下文的类加载器
  2. 各种模型类的类加载器

如上所述,可以将(1)指定为JAXBContext.newInstance()中的参数,但是仅当将模型指定为包名称而不是单个模型类时才可以.这意味着JAXB必须自己查找类,并且它唯一可以使用的类加载器是(1)-如果它们分散在多个包中,则无法看到所有模型类.

As described above, (1) can be specified as a parameter in JAXBContext.newInstance(), but only when specifying the model as package names instead of individual model classes. This means JAXB has to look up the classes on its own, and it the only classloader it can use to do that is (1) - which can't see all the model classes if they are spread across multiple bundles.

另一个线程(为什么可以在Apache Felix中运行时,JAXB找不到我的jaxb.in​​dex吗?)告诉我,JAXB默认使用线程上下文类加载器来定位上下文实现.将其设置为可以看到实现的类加载器(例如,我自己的捆绑包的实现)足以使JAXB找到自己的实现,这使我可以***地使用类数组调用我的首选版本的newInstance().而且由于这些类已经被加载,因此JAXB可以按原样使用它们,而不必关心它们的不同类加载器.

Another thread (Why can't JAXB find my jaxb.index when running inside Apache Felix?) taught me that JAXB defaults to using the thread context classloader to locate the context implementation. Setting that to a classloader that sees the implementation (e.g. that of my own bundle) is sufficient to make JAXB find its own implementation, which leaves me free to call my preferred version of newInstance() with an array of classes. And since these classes have already been loaded, JAXB can use them as is and doesn't have to care about their different classloaders.

简而言之:

Class[] myClasses = getModelClasses(); // gather all model classes, which may have different classloaders
Thread thread = Thread.currentThread();
ClassLoader originalClassLoader = thread.getContextClassLoader();
thread.setContextClassLoader(getClass().getClassLoader()); // my own bundle's classloader
JAXBContext context = JAXBContext.newInstance(myClasses);
thread.setContextClassLoader(originalClassLoader); // reset context classloader

上下文类加载器的操作内容可以包装在AutoCloseable中,这使我可以将JAXBContext实例包装在try-with-resources块中.

The context classloader manipulation stuff can be wrapped in an AutoCloseable, allowing me to simply wrap the JAXBContext instantiation in a try-with-resources block.