Apache POI 5 and XMLBeans Classpath issues - apache-poi

I tried answering on the following post, but I don't have the "reputation" and really do not have time to hunt down 10 questions to answer.
Runtime Exception - POI 5 and xmlbeans
With POI 5 and XMLBeans 4 (or 5) in WebLogic server there is a classloader issue where it will try to use the underlying XMLBeans jar in the WebLogic server modules directory.
When packaging in an EAR you can use the weblogic-application.xml descriptor to override class loading with .
However, listing the POI and dependencies packages here will result in further errors.
The class SchemaTypeLoaderImpl is looking in the new (org.apache.xmlbeans.metadata) AND old (schemaorg_apache_xmlbeans) packages.
So you should also include the old package in the override list.
Now SchemaTypeLoaderImpl also tries to load the TypeSystemHolder classes using ClassLoader.getResource before it tries to look it up with Class.forName.
To fix this issue you need to prevent it from finding the old classes, as the previous package override is only giving your application bundled library priority over the underlying server libraries. It is not preventing it from finding these out of date classes and trying to load them as well.
This can be done by using for these resources.
NOTE that I am only using basic XSSFWorkbook XLS functionality!
You may need to track down other resources if you use other POI functionality.
For example the following weblogic-application.xml descriptor allows your application to use bundled POI/XMLBeans libraries and ignore the old resources.
<prefer-application-packages>
<package-name>org.apache.commons.collections4.*</package-name>
<package-name>org.apache.commons.compress.*</package-name>
<package-name>org.apache.poi.*</package-name>
<package-name>org.apache.xmlbeans.*</package-name>
<package-name>org.openxmlformats.*</package-name>
<package-name>schemaorg_apache_xmlbeans.*</package-name>
</prefer-application-packages>
<prefer-application-resources>
<resource-name>schemaorg_apache_xmlbeans/system/sXMLCONFIG/TypeSystemHolder.class</resource-name>
<resource-name>schemaorg_apache_xmlbeans/system/sXMLLANG/TypeSystemHolder.class</resource-name>
<resource-name>schemaorg_apache_xmlbeans/system/sXMLSCHEMA/TypeSystemHolder.class</resource-name>
<resource-name>schemaorg_apache_xmlbeans/system/sXMLTOOLS/TypeSystemHolder.class</resource-name>
</prefer-application-resources>

Related

log4j "bridge" and the RootLogger class

We're trying to force an old vendor-provided Java-program (a JAR) to use log4j2, with the help of the log4j "bridge".
To do this, I:
Deleted all entries starting with org/apache/log4j/* from the vendor's JAR
Added the log4j-1.2-api-2.17.1.jar and the regular log4j-*-2.17.1.jar files to CLASSPATH
The program dies unable to find the org/apache/log4j/spi/RootLogger. Listing the contents of the bridge JAR, I find several classes under the org/apache/log4j/spi/, but the RootLogger is, indeed, missing.
How do I deal with this?
The newest version 2.17.2 of Log4j2 contains a couple of dozen of fixes to the Log4j 1.x bridge (cf. changelog).
Among them the org.apache.log4j.RootLogger class has been added to provide binary compatibility with Log4j 1.x.
Warning: many of the added classes are no-ops and just prevent ClassNotFoundExceptions as the one in your question.

flink InputStream of class class org.apache.commons.compress.archivers.zip.ZipFile$1 is not implementing InputStreamStatistics

I was trying to load an excel into POI workbook in a Flink program. Has an error like this.
Caused by: java.lang.IllegalArgumentException: InputStream of class class org.apache.commons.compress.archivers.zip.ZipFile$1 is not implementing InputStreamStatistics.
at org.apache.poi.openxml4j.util.ZipArchiveThresholdInputStream.(ZipArchiveThresholdInputStream.java:63)
at org.apache.poi.openxml4j.util.ZipSecureFile.getInputStream(ZipSecureFile.java:147)
at org.apache.poi.openxml4j.util.ZipSecureFile.getInputStream(ZipSecureFile.java:34)
at org.apache.poi.openxml4j.util.ZipFileZipEntrySource.getInputStream(ZipFileZipEntrySource.java:66)
at org.apache.poi.openxml4j.opc.ZipPackage.getPartsImpl(ZipPackage.java:258)
at org.apache.poi.openxml4j.opc.OPCPackage.getParts(OPCPackage.java:725)
at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:275)
at org.apache.poi.openxml4j.opc.OPCPackage.open(OPCPackage.java:181)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.(XSSFWorkbook.java:323)
notice a test https://github.com/apache/poi/blob/f509d1deae86866ed531f10f2eba7db17e098473/src/ooxml/testcases/org/apache/poi/openxml4j/util/TestZipSecureFile.java here that mention this. But how to work around it. Thanks!
You have to include a newer version of commons-compress and shade it (there ar different plugins in Maven, Gradle, SBT). Alternatively, you can use the HadoopOffice library, which has native Flink support, to read/write Excel files (https://github.com/zuinnote/hadoopoffice/wiki) and it has an example on how to shade the dependency correctly (see https://github.com/ZuInnoTe/hadoopoffice/wiki/Using-Apache-Flink-to-read-write-Excel-documents)

JDK 9: JUnit 5 test compile with SpringExtension produces java.lang.NoClassDefFoundError: org/w3c/dom/ls/DocumentLS

I believe this problem not to be related to module exclusions in JDK 9 (as with java.se.ee), but rather with the fact that JDK 9 includes a newer version of org.w3c.dom.ls in the java.xml module that does not have the DocumentLS class.
The important bit of the stack trace is this:
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from class path resource [spring-test/test-container.xml]; nested exception is java.lang.NoClassDefFoundError: org/w3c/dom/ls/DocumentLS
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:414)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:336)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:304)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:181)
Even if I include a runtime dependency with this class, like xerces:xerces 2.4.0, the JDK java.xml module is preferred (I guess).
I am using Gradle 4.1. Is there any way to restrict the scope of a
JDK provided module?
As you have correctly analyzed, the package org.w3c.dom.ls is present in the platform module java.xml. Any class on the class path that is in the same package will be ignored. That's called a split package and several fixes exist - the following two might help you.
Patch java.xml
You can add the classes of the Xerxes JAR to the java.xml module with --patch-module:
java --patch-module java.xml=xerxes-4.0.0.jar ...
I've never tried that with a JAR that contains some of the same classes. As I understand it, the JDK classes will then be replaced with the Xerxes classes, which means they better be a fully binary compatible replacement.
Upgrade java.xml
Another hope is to replace java.xml with the upgrade module path:
The upgrade module path (--upgrade-module-path) contains compiled definitions of modules intended to be used in place of upgradeable modules built-in to the environment (compile time and run time).
You face two problems:
the upgrade module path is supposed to be used only for upgradable modules (which java.xml is not), but I think I've read somewhere that that's not enforced (yet?) - didn't try it
the artifact you replace java.xml with needs to be fully binary compatible update - would that be the case for Xerxes?
From what I can tell, DocumentLS is from a 2002 draft of the W3C API, it doesn't appear to have made it into a released version. It looks like xerces-2.4.0 (from 2006?) includes it but newer versions don't. So upgrading to a more recent Xerces may be needed here. If Spring really depends on DocumentLS then it will need to be updated too.

May I use jxls and apache poi together?

I'm making an application to analize some data and the result must be presented in excel files. In that sense I started to use Apache POI (3.11). Due to some reports consumes a lot of time and memory to be reproduce, I made an investigation and I found jxls, after some test I thought was the solution. But now I found a problem: can´t work both frameworks together.
I have to update Apache POI from 3.11 to 3.14, in order to work with jxls-2.3.0
I made an extra package in order to make my tests with jxls, not problem
I try to migrated one of my classes from Apache POI to jxls, and a I got this error: java.lang.IllegalStateException: Cannot load XLS transformer. Please make sure a Transformer implementation is in classpath. This is the code of my method:
private void prepareNewReport(File excelFile) {
List perforaciones = makePerforacionReport
.makePerforacionData(escenario);
try (InputStream is = ReportePerforacionTotalDialog.class
.getResourceAsStream("PerforacionTotal_template.xls")){
try (OutputStream os = new FileOutputStream(excelFile)) {
Context context = new Context();
context.putVar("perforaciones", perforaciones);
JxlsHelper.getInstance().processTemplate(is, os, context);
LOGGER.logger.log(Level.INFO, "Archivo de perfortacion generado con éxito");
}
} catch (IOException e) {
LOGGER.logger.log(Level.SEVERE, "Problemas buscando el archivo", e);
}
}
How could be this possible?. In the same project I have my test class, just another package and its working fine. As you can see it´s not so much different from the example in the jxls page and the imports are the same.
But even worst, when I tried to make clean & build of my project, then I got this other error:
java.lang.RuntimeException: com.sun.tools.javac.code.Symbol$CompletionFailure: class file for org.openxmlformats.schemas.officeDocument.x2006.docPropsVTypes.CTArray not found
I looked at every library that I importede in order to work with jxls and apache poi, and that´s rigth, that class is not there. Just to see if there a conflict among these two framewoks, I eliminated from the class path all libraries needed to use jxls. Clean & build again, and not problem, I have my .jar file to send to my customer, but incomplete.
I could try to replace all classes that use Apache POI, but that means a lot of work, since POI is used in my project to read excel files with data many times and to write another many files to excel. I planned to use jxls in order to take advantage of use templates.
I will apreciate any help or suggestion.
For the first error, it would appear that the JXLS transformer for Apache POI is missing in your classpath when running the application. Check the JXLS getting started info here: http://jxls.sourceforge.net/getting_started.html
As it is explained in Transformers section (see Main Concepts)) Jxls core module does not depend on any specific Java-Excel library and works with Excel exclusively through a predefined interface. Currently Jxls supplies two implementations of this interface in separate modules based on the well-known Apache POI and Java Excel API libraries.
If you're using maven, be sure to include in your pom.xml the jxls-poi dependency listed on the JXLS getting started page:
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls-poi</artifactId>
<version>1.0.9</version>
</dependency>
For the second issue, org.openxmlformats.schemas.officeDocument.x2006.docPropsVTypes.CTArray is not in the apache POI ooxml schemas jar files for either 3.11 (poi-ooxml-schemas-3.11-20141221.jar) or 3.14 (poi-ooxml-schemas-3.14-20160307.jar). POI uses a stripped down set of ooxml schema classes, you will need to get the ooxml schemas complete jar from http://central.maven.org/maven2/org/apache/poi/ooxml-schemas/1.3/ or if you're using maven (or another build tool), get the dependency for your build from https://mvnrepository.com/artifact/org.apache.poi/ooxml-schemas/1.3
e.g for maven:
<!-- https://mvnrepository.com/artifact/org.apache.poi/ooxml-schemas -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.3</version>
</dependency>
Be sure to remove the poi-ooxml-schemas dependency from your maven pom.xml so that ooxml-schemas above takes precedence instead.

XSSFWorkbook poi: adding image IOUtils toByteArray unfined error

To insert image to excel using POI:XSSF
I am using maven poi dependency:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.8</version>
</dependency>
AND code as :
InputStream my_banner_image = new FileInputStream("input.png");
byte[] bytes = IOUtils.toByteArray(my_banner_image);
int my_picture_id = wb.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
I am getting these errors:
1) The method toByteArray(InputStream) is undefined for the type IOUtils
2) PICTURE_TYPE_PNG cannot be resolved or is not a field
Any help would be appriciated. Thanks.
Promoting a comment to an answer:
The method you want to use is very much present in Apache POI 3.11, and you can see full details about it in the POI Javadocs.
As detailed on the POI Components page, defining a Maven dependency on poi-ooxml will pull in the main poi component jar, which is where the IOUtils class lives, so that bit is fine
What you have in this case (based on comments) is a second, older copy of POI on your classpath. You need to remove this older POI jar (or POI jars), in common with most Java projects Apache POI will only work properly if all of the POI jars are from the same version, and no old ones are present.
Because it's a fairly common problem - lots of frameworks ship old copies of POI for example - there's a POI FAQ entry on this very thing. If you can't find the old jar by hand, you can use the code given there to work out where the old jar is to remove it.
Also, one other thing to bear in mind - many many projects provide a class called IOUtils - make sure the one you have imported into your code is org.apache.poi.util.IOUtils and not something else!

Resources