JAXB内部实现接口com.sun.xml.bind.namespacePrefixMapper的类加载器问题



我需要帮助解决以下问题:我将Websphere Liberty 19.0.0.9与Oracle和IBM Java 1.8一起使用,以运行包含EJB的旧应用程序(EAR(,该应用程序使用JAXB序列化XML。应用程序需要控制XML命名空间定义和前缀,并通过向javax.XML.bind.Marshaller.setProperty提供com.sun.XML.bind.namespacePrefixMapper的实现来实现这一点,其属性为"com.sun.xm.bind.namespacePrefixMapper"。在运行时,加载实现类时会出现错误java.lang.NoClassDefFoundError:com/sun/xml/bind/mashaller/NamespacePrefixMapper。server.xml包含特性javaee-8.0,freedom的JAXB实现wlp-19.0.0.9\lib\com.ibm.ws.JAXB.tools.2.2.10_1.0.32.jar包含类com.sun..xml.bind.marshaller.NamespacePrefixMapper.

我试图通过将jaxb-impl-2.4.jar放入EAR/lib来解决这个问题(这是错误的方式,因为jaxb是由JEE提供的(,但随后在com.sun.xml.bind.v2.runtime.MarshallerImpl.setProperty(MarshallerImpl.java:511(中发生了错误,因为检查if(!(value instanceof NamespacePrefixMapper((失败,因为实现的Classloader(AppClassLoader(为类NamespacePrefixMapper提供了另一个类对象,而不是MarshallerImpls的Classloader(org.eclipse.osgi.internal.loader.EquinoxClassLoader(。但这表明自由可以访问NamespacePrefixMapper。

我多次尝试在加载实现和MarschallerImpl时使用相同的类加载器,并试图通过server.xml中的classloder设置来解决这个问题。没有成功。我知道不建议使用这种特定于JAXB实现的类,但应用程序是以这种方式开发的,不能轻易更改。

告诉我如何说服liberty将NamespacePrefixMapper类提供给应用程序类加载器,或者在MarschallerImpl中使用应用程序类加载程序NamespacePrefixMapper,我们将不胜感激。非常感谢。

//The implementation class looks for example like this:
public class MyNamespacePrefixMapperImpl extends com.sun.xml.bind.marshaller.NamespacePrefixMapper {...}
JAXBContext c = JAXBContext.newInstance(some mapped class);
Marshaller m = c.createMarshaller();
com.sun.xml.bind.marshaller.NamespacePrefixMapper mapper = new MyNamespacePrefixMapperImpl();// Here the NoClassDefFoundError occurs.
m.setProperty("com.sun.xml.bind.namespacePrefixMapper", mapper); // Here the instanceof check fails if jaxb-impl.jar is in EAR/lib.

这是一个不稳定的情况,没有简单的解决方案。Liberty试图"隐藏"内部包,以避免用户希望实现的版本与框架提供的版本略有不同的情况——这个问题最明显的例子是在传统的was中,用户希望使用与was附带的不同版本的Jakarta Commons Logging——这需要用户提供自己的,要么在一个独立的共享库中,要么使用其他父类的最后一个类加载技巧使其工作。Liberty通过将内部实现与用户应用程序隔离来避免这些问题。

因此,当用户想要使用与Liberty提供的不同版本的第三方库时,这非常有效,但正如您所发现的,当您的遗留应用程序依赖于那些隐藏/隔离的第三方库时,这种方法就不那么有效了。

最理想的解决方案是重构应用程序代码,使其不依赖于内部JAXB类——拥有更多JAXB专业知识的人可能能够帮助实现这一点。。。但这听起来可能不可行,所以另一种选择是创建用户功能。用户功能本质上是Liberty运行时的扩展,因此它可以访问用户应用程序无法访问的包。它还允许您添加包作为用户应用程序的API,因此您可以使用用户功能将com.sun.xml.bind.marshaller添加为公共API,然后您的用户应用程序可以自由扩展它。您还可以将MyNamespacePrefixMapperImpl类包含在用户功能中,并在那里注册,以便它自动应用于服务器中的所有应用程序。

您可以在此处找到有关用户功能的更多信息:https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/twlp_feat_example.html

希望这能有所帮助,Andy

最新更新