How to use Apache POI in OSGi

2019-02-25 06:49发布

问题:

I want to use Apache POI in OSGi to write an Excel workbook with the streaming, OOXML API (SXSSF). The streaming API is available since POI 3.9.

As the latest Apache POI 3.11 jars are not bundles: What's the best way to get POI working in OSGi?

I tried two approaches:

  1. embed the jars directly in the only bundle which will be using them
  2. use POI jars prewrapped as bundles

I am despairing in getting all dependencies together.

First about embedding the POI jar in my bundle: my bndtools file contains

-buildpath:  \
...
libs/dom4j-1.6.1.jar;version=file,\
libs/poi-3.11.jar;version=file,\
libs/poi-ooxml-3.11.jar;version=file,\
libs/poi-ooxml-schemas-3.11.jar;version=file

Private-Package:  \
...
org.openxmlformats.schemas.*,\
org.apache.poi.*,\
org.dom4j.*,\
com.microsoft.schemas.office.x2006.*,\
schemaorg_apache_xmlbeans.*,\
schemasMicrosoftComOfficeExcel.*,\
schemasMicrosoftComOfficeOffice.*,\
schemasMicrosoftComVml.*

This results in a bundle which imports many, many things like for example org.bouncycastle.asn1.x509 and org.junit. I don't plan to encrypt or test in my application - so these two are probably somehow "optional". How can I specify this? Is there a good way of collecting all these dependencies?

Note: at least org.apache.commons.codec and com.sun.msv.datatype.xsd.lib are additionally required, but they are already bundles.


Using prewrapped jars, I tried using org.apache.servicemix.bundles.poi 3.9_2. This also requires dom4j so I used the prewrapped org.apache.servicemix.bundles.dom4j but that requires at least version 1.0 of javax.xml.stream which my JVM/Felix OSGi advertises as "only" version 0.0.0.1_007_JavaSE. I fixed this by hand (ugly), but then got stuck on another dependency.

What's the good way?

回答1:

We use Gradle with bnd-platform to build OSGi bundles for our applications based on Maven dependencies. No sure if this is "the good way", but this is how we build the target platform for our OSGi based applications, Apache POI being part of that. It's especially useful in cases where you have to do adaptions to bundles (e.g. make JUnit optional) or merge JARs (e.g. due to classloading issues in OSGi) to make them work.

I set up an example build with an Apache POI bundle (and implicitly, its POM-defined dependencies) on GitHub. You can clone it (sample-poi branch) and try it running ./gradlew clean bundles. Created bundles will be in build/plugins.

Please note that any optional Maven dependencies will not be included by default and have to be added manually to the build, if you need them (due to limitations in Gradle).



回答2:

I don't have a working example of this work around but this bit of documentation may be helpful to you.

Can POI be used with OSGI?

Starting with POI 3.16 there's a workaround for OSGIs context classloader handling, i.e. it replaces the threads current context classloader with an implementation of limited class view. This will lead to IllegalStateExceptions, as xmlbeans can't find the xml schema definitions in this reduced view. The workaround is to initialize the classloader delegate of POIXMLTypeLoader , which defaults to the current thread context classloader. The initialization should take place before any other OOXML related calls. The class in the example could be any class, which is part of the poi-ooxml-schema or ooxml-schema: POIXMLTypeLoader.setClassLoader(CTTable.class.getClassLoader());