前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OSGi跨bundle调用,jaxb-impl异常

OSGi跨bundle调用,jaxb-impl异常

作者头像
有一只柴犬
发布2024-01-25 11:24:35
2050
发布2024-01-25 11:24:35
举报
文章被收录于专栏:JAVA体系

问题

环境:JDK11

为什么是JDK11,由于jaxb是作为JDK8的一部分,在JDK11中已经被剥离出来需要单独引入。

项目中使用osgi架构,在处理xml解析的实现中使用了jdk自带的Javax.xml.bind包。在单模块结构工程中都没有问题,但是引到插件化模式工程结构中,会提示找不到JaxbContext的工厂类而报错。具体报错信息如下:

代码语言:javascript
复制
Caused by: javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:278) ~[na:na]
    at javax.xml.bind.ContextFinder.find(ContextFinder.java:421) ~[na:na]
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:721) ~[na:na]
    at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:662) ~[na:na]
    at com.ruijie.pctool.plugins.device.pojo.bo.PluginLoaderExt.fromXml(PluginLoaderExt.java:79) ~[na:na]
    ... 32 common frames omitted
Caused by: java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory
    at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:476) ~[na:na]
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589) ~[na:na]
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ~[na:na]
    at org.eclipse.osgi.internal.framework.ContextFinder.loadClass(ContextFinder.java:135) ~[na:na]
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ~[na:na]
    at javax.xml.bind.ServiceLoaderUtil.nullSafeLoadClass(ServiceLoaderUtil.java:122) ~[na:na]
    at javax.xml.bind.ServiceLoaderUtil.safeLoadClass(ServiceLoaderUtil.java:155) ~[na:na]
    at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:276) ~[na:na]
    ... 36 common frames omitted
JavaFX Application Thread

导入的依赖:(这里shade包是继承了jaxb的api,impl,runtime等包的合集)

代码语言:javascript
复制
<dependency>
    <groupId>com.ruijie.osgi.thirdparty</groupId>
    <artifactId>javax.xml.bind.shade</artifactId>
    <version>2.3.1.v202203241600</version>
</dependency>

原因分析

在引入的包中,所提供的工厂类为com.sun.xml.bind.v2.ContextFactory,并不是错误提示的com.sun.xml.internal.bind.v2.ContextFactory;

其实jaxb提供了几种构建jaxbcontext的方式,如果都匹配不到,那么会使用系统默认指定的com.sun.xml.internal.bind.v2.ContextFactory来构建,但是不知道为什么指定了一个jar不存在的包路径:

代码语言:javascript
复制
javax.xml.bind.ContextFinder#find(java.lang.String, java.lang.String, java.lang.ClassLoader, java.util.Map)

JaxbContext源码

代码语言:javascript
复制
static JAXBContext find(String factoryId, String contextPath, ClassLoader classLoader, Map properties) throws JAXBException {
        if (contextPath != null && !contextPath.isEmpty()) {
            Class[] contextPathClasses = ModuleUtil.getClassesFromContextPath(contextPath, classLoader);
            String factoryClassName = jaxbProperties(contextPath, classLoader, factoryId);
            if (factoryClassName == null && contextPathClasses != null) {
                factoryClassName = jaxbProperties(contextPathClasses, factoryId);
            }
 
            if (factoryClassName != null) {
                return newInstance(contextPath, contextPathClasses, factoryClassName, classLoader, properties);
            } else {
                String factoryName = classNameFromSystemProperties();
                if (factoryName != null) {
                    return newInstance(contextPath, contextPathClasses, factoryName, classLoader, properties);
                } else {
                    JAXBContextFactory obj = (JAXBContextFactory)ServiceLoaderUtil.firstByServiceLoader(JAXBContextFactory.class, logger, EXCEPTION_HANDLER);
                    if (obj != null) {
                        ModuleUtil.delegateAddOpensToImplModule(contextPathClasses, obj.getClass());
                        return obj.createContext(contextPath, classLoader, properties);
                    } else {
                        factoryName = firstByServiceLoaderDeprecated(JAXBContext.class, classLoader);
                        if (factoryName != null) {
                            return newInstance(contextPath, contextPathClasses, factoryName, classLoader, properties);
                        } else {
                            Class ctxFactory = (Class)ServiceLoaderUtil.lookupUsingOSGiServiceLoader("javax.xml.bind.JAXBContext", logger);
                            if (ctxFactory != null) {
                                return newInstance(contextPath, contextPathClasses, ctxFactory, classLoader, properties);
                            } else {
                                logger.fine("Trying to create the platform default provider");
                                return newInstance(contextPath, contextPathClasses, ModuleUtil.DEFAULT_FACTORY_CLASS, classLoader, properties);
                            }
                        }
                    }
                }
            }
        } else {
            throw new JAXBException(Messages.format("ContextFinder.NoPackageInContextPath"));
        }
    }

1、首先,寻找系统是否自定义jaxb.properties,指明所需的工厂类全限定名

2、其次,寻找系统是否配置了系统变量javax.xml.bind.JAXBContextFactory来指定工厂对象

3、接着,寻找jaxb包提供的META-INF/servies/javax.xml.bind.JAXBContextFactory配置文件,里面配置了所需的工厂类全限定名

4、若还是没有,lookuposgibundle寻找

5、若还是没有,就构建系统默认指定的com.sun.xml.internal.bind.v2.ContextFactory;由于该路径下不存在这个类,所以直接报错

按理,jaxb包提供的META-INF/servies/javax.xml.bind.JAXBContextFactory这个文件存在的情况下,为什么还是没被识别到呢?猜测由于OSGi的隔离机制,在跨bundle使用过程中读取不到该配置文件。

解决

由于jaxb-api提供了SPI的扩展机制,基于他的实现很多,所以集成了如下的依赖解决该问题:

代码语言:javascript
复制
<!-- jaxb-api实现需要的依赖 -->
<dependency>
    <groupId>com.ruijie.osgi.thirdparty</groupId>
    <artifactId>javax.karta.xml.bind-api</artifactId>
    <version>2.3.3.v20220331-2000</version>
</dependency>
<dependency>
    <groupId>com.ruijie.osgi.thirdparty</groupId>
    <artifactId>javax.karta.activation</artifactId>
    <version>1.2.2.v20220331-2000</version>
</dependency>
<dependency>
    <groupId>com.ruijie.osgi.thirdparty</groupId>
    <artifactId>com.sun.xml.bind.jaxb-osgi</artifactId>
    <version>2.3.6.v2022331-2000</version>
</dependency>
<dependency>
    <groupId>com.ruijie.osgi.thirdparty</groupId>
    <artifactId>org.glassfish.osgi-resource-locator</artifactId>
    <version>2.4.0.v20220331-2000</version>
</dependency>

问题解决。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-02-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题
  • 原因分析
    • JaxbContext源码
    • 解决
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档