RCP集成BIRT 4.13:Rhino脚本如何加载其他OSGi Bundle类?
问题描述
在基于Java 17的2023-09版本RCP应用中集成4.13版本BIRT报表引擎,需求是Bundle B向包含报表引擎的Bundle R提交rptdesign文件。Bundle B的报表脚本中使用了该Bundle内的myapp.mech.model.Dao类,且该类所在包已由Bundle B导出。
当前在Bundle R中设置类加载器的代码如下:
Bundle bundle = org.eclipse.core.runtime.Platform.getBundle(getBundleIdFromUrl(reportDesign)); BundleWiring bundleWiring = bundle.adapt(BundleWiring.class); config.getAppContext().put(EngineConstants.APPCONTEXT_CLASSLOADER_KEY, bundleWiring.getClassLoader()); config.getAppContext().put(EngineConstants.APPCONTEXT_DATASET_CACHE_OPTION, Boolean.FALSE.toString()); config.getAppContext().put(EngineConstants.REFRESH_DATA, Boolean.TRUE.toString()); IReportEngineFactory factory = (IReportEngineFactory) Platform.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY); engine = factory.createReportEngine(config);
执行报表脚本时出现类未找到错误:
A BIRT exception occurred. See next exception for more information. TypeError: [JavaPackage myapp.mech.model.Dao] is not a function, it is object. (/report/data-sets/script-data-set[@id="411"]/method[@name="open"]#1) org.eclipse.birt.data.engine.core.DataException: Fail to execute script in function __bm_OPEN(). Source: ------ " + model = new Packages.myapp.mech.model.Dao();
注:Bundle R内的报表可正常运行
解决方案
针对该类加载问题,可从以下方向调整:
1. 调整类加载器设置时机
当前在创建引擎时设置类加载器,可尝试在加载报表设计文件后,为ReportDesignHandle单独设置类加载器:
// 获取reportDesignHandle后添加 reportDesignHandle.getModuleHandle().setClassLoader(bundleWiring.getClassLoader());
2. 使用复合类加载器
OSGi环境下单独用Bundle B的类加载器可能无法访问BIRT引擎自身类,需构建包含Bundle B和Bundle R类加载器的复合加载器:
ClassLoader bundleBClassLoader = bundleWiring.getClassLoader(); ClassLoader bundleRClassLoader = getClass().getClassLoader(); ClassLoader compositeClassLoader = new ClassLoader(bundleRClassLoader) { @Override protected Class<?> findClass(String name) throws ClassNotFoundException { try { return bundleBClassLoader.loadClass(name); } catch (ClassNotFoundException e) { return super.findClass(name); } } }; config.getAppContext().put(EngineConstants.APPCONTEXT_CLASSLOADER_KEY, compositeClassLoader);
3. 检查OSGi包配置
- 确认Bundle B的
MANIFEST.MF正确导出目标包,且范围覆盖Bundle R:Export-Package: myapp.mech.model;version="1.0.0" - 确认Bundle R的
MANIFEST.MF已导入该包:Import-Package: myapp.mech.model;version="[1.0.0,2.0.0)"
4. 调整脚本类引用方式
尝试去掉Packages前缀直接引用类:
model = new myapp.mech.model.Dao();
5. 验证类加载器有效性
设置类加载器前先验证能否加载目标类,排除类路径问题:
try { Class<?> daoClass = bundleBClassLoader.loadClass("myapp.mech.model.Dao"); System.out.println("成功加载类:" + daoClass.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); }
内容的提问来源于stack exchange,提问作者paul
相关产品推荐
相关产品推荐

