I recently had a requirement to update an existing XPages-based application that uses Apache POI (the Java API for Microsoft Documents) to generate spreadsheet files.
Now this post is not specifically about Apache POI, or how to use it with Domino and XPages, but more about an issue that I hit whilst updating the application.
The existing application set-up involved:
- The required Apache POI JAR files were located in a "WebContent\WEB-INF\lib" folder
- The Java Build Path of the application included the applicable Apache POI JAR files
- There were several Java source files in the application that made use of the Apache POI functionality
- There were several front-end XPages that used the back-end Java source files (returning the resulting spreadsheet data as a file to the user)
Updating the application
The initial updates to the application went smoothly. I added the new POI JAR files to the application and attempted a clean/rebuild. A few small changes were required (related to cell styling and data formatting) but after that the application built without any errors. I replaced the design of my test application database and opened the various XPages which all resulted in a correct XLS file being returned.
I then moved onto to updating the Java source files in the application to create XLSX files. I modified the first Java source file in the application template, did a rebuild, and then replaced the design of my test application. I then tested the changes by opening the applicable XPage which successfully returned a spreadsheet.
However, after updating the second Java source file in the application template and deploying it to my test application, I started to get errors. Both of the updated XPages failed to open, and the Domino server reported the following error.
java.lang.BootstrapMethodError: java.lang.LinkageError: loading constraint violation when overriding method "org/apache/poi/ooxml/POIXMLRelation$NoArgConstructor.init()Lorg/apache/poi/ooxml/POIXMLDocumentPart;" during creation of class "org/apache/poi/xssf/usermodel/XSSFRelation$$Lambda$89/0000000019CA3C90": loader "java/lang/InternalAnonymousClassLoader@4d10b092" of class "org/apache/poi/xssf/usermodel/XSSFRelation$$Lambda$89/0000000019CA3C90" and loader "com/ibm/domino/xsp/module/nsf/ModuleClassLoader$DynamicClassLoader@e77e48ff" of class "org/apache/poi/ooxml/POIXMLRelation$NoArgConstructor" have different types for the method signature
I did some searching to see the issue had been seen before, but did not find anything that matched. I found a few pages that described similar issues and even tried some of the suggested solutions, but nothing resolved the issue.
What I did discover however was that after I restarted my test Domino server, the issue disappeared. Or at least it disappeared until I deployed another update to the test application at which point the error returned.
I tried some more tests and discovered that restarting the Domino server HTTP task also resulted in the error disappearing... but only until I deployed another update to the application. Ideally I did not want to deploy the application knowing that any future updates would require a restart of the HTTP task. Plus, since it was not clear why the error was happening, I could not guarantee the issue would only occur as and when updates were applied.
Since in the test environment everything appeared to work fine up until the application design was updated, I decided to see if moving the Apache POI JAR files out the application would help.
I opted to try building an OSGi plugin that would wrap the Apache POI JAR files. This way I could easily deploy it to the production environment (which already had an Update Site database configured) and it would also then be available to other applications.
There are a number of great articles and presentations out there covering the topic of creating plugins, but the one I found most useful was Wrap an existing JAR file into a plug-in.
I initially tried using my existing Domino Designer 11.0.1 client to create the plugin, feature and update site, but kept hitting issues. In the end, I switched to using an Eclipse client installation, set-up to use the files of my development Domino server. Using this set-up, I was able to create the plugin, feature and update site without any issues.
I installed the new plugin/feature in my Designer client and then applied the following changes to the application template:
- Updated the build settings and removed all references to POI JAR files in the local database
- Removed the POI JAR files from the application template
- Changed the XSP Properties of the application to include the new "Apache POI" XSP Library
- Ran a clean/rebuild of the template which completed successfully
I then installed the plugin/feature onto my development Domino server, deployed the new application design, restarted HTTP and tested all of the XPages that generated spreadsheets. They all worked 🙂
I then tried some tests by updating a third source Java file in the application so it generated an XLSX file. Deployed the design update and this time everything worked without needing to restart either the HTTP task or the Domino server.
So the solution (or at least the work-around!) in this case was to move the Apache POI JAR files out of the application and put them into an OSGi plugin/feature.