[
https://issues.apache.org/jira/browse/COMPRESS-221?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13594040#comment-13594040
]
Matt Quigley commented on COMPRESS-221:
---------------------------------------
Note that a possible solution is to have a try-catch on a static method which
will fail when the class loader tries loading a class.
For example, {{XZUtils}} does not import any classes not in the Compress
project, so we can add a static method {{isAvailable()}} which calls a class
which does import classes not in the Compress project:
{code}
/**
* This is a helper method to see if the XZ library is available.
*
* @return {@code true} if the XZ library is available.
*/
public static boolean isAvailable() {
try {
XZCompressorInputStream.isAvailable();
return true;
} catch (Throwable t) {
return false;
}
}
{code}
The following will always return {{true}} when the class loader can load the XZ
library, but will throw a {{NoClassDefFoundError}} when its class cannot be
loaded due to the imports problem.
{code}
/**
* This is a helper method to see if the XZ library is available. If the
library is not available, then the class
* loader will throw a {@code NoClassDefFoundError}.
*
* @return {@code true} if the XZ library is available.
*/
public static boolean isAvailable() {
return true;
}
{code}
And then before the XZ library is used, we can simply check to see if it is
available:
{code}
if (XZUtils.isAvailable()) {
if (XZCompressorInputStream.matches(signature,
signatureLength)) {
return new XZCompressorInputStream(in);
}
}
{code}
> Compress cannot run without XZ included
> ---------------------------------------
>
> Key: COMPRESS-221
> URL: https://issues.apache.org/jira/browse/COMPRESS-221
> Project: Commons Compress
> Issue Type: Bug
> Affects Versions: 1.4.1
> Reporter: Matt Quigley
>
> In previous versions of Compress, we used the Compress library in our
> application without requiring any other libraries. Since the introduction of
> XZ, the library crashes because it does not dynamically try to find the XZ
> classes. Our application does not use or need XZ, and we _cannot_ add another
> ~100KB file to our application.
> To reproduce:
> {code}
> try {
> // <properties><mimeTypeRepository resource="/etc/tika-mimetypes.xml"
> magic="true"/></properties>
> tika = new
> TikaConfig(getClass().getClassLoader().getResourceAsStream("etc/tika-config.xml"));
> } catch (Throwable t) {
> t.printStackTrace();
> throw new MimeTypeException("Cannot load tika-config.xml", t);
> }
> detector = tika.getDetector();
> MediaType contentType = MediaType.OCTET_STREAM;
> contentType = detector.detect(tika, metadata); // error here
> {code}
> Calling {{Detector.detect(InputStream, Metadata)}} causes a
> {{NoClassDefFoundError}} because it is trying to find the XZ files using a
> direct reference to the XZ classes. {{Detector.detect:61}} uses
> {{ZipContainerDetector.detect}} to use {{CompressorInputStream
> createCompressorInputStream(InputStream)}}.
> The problem in {{public CompressorInputStream
> createCompressorInputStream(InputStream)}} is it directly calls static
> methods on the {{XZCompressorInputStream}} class which aren't in the
> classpath.
> {code}
> if (BZip2CompressorInputStream.matches(signature, signatureLength)) {
> return new BZip2CompressorInputStream(in);
> }
> if (GzipCompressorInputStream.matches(signature, signatureLength)) {
> return new GzipCompressorInputStream(in);
> }
> if (XZCompressorInputStream.matches(signature, signatureLength)) {
> return new XZCompressorInputStream(in);
> }
> if (Pack200CompressorInputStream.matches(signature, signatureLength))
> return new Pack200CompressorInputStream(in);
> {code}
> Ass you can see, the {{XZCompressorInputStream.matches()}} method is a static
> method. When the class loader loads this class, it tries to load the import
> statements at the top of {{XZCompressorInputStream}}:
> {code}
> import org.apache.commons.compress.compressors.CompressorInputStream;
> import org.tukaani.xz.SingleXZInputStream;
> import org.tukaani.xz.XZ;
> import org.tukaani.xz.XZInputStream;
> {code}
> And, since these {{org.tukaani.xz}} classes don't exist, a
> {{NoClassDefFoundError}} exception is thrown.
> {code}
> java.lang.NoClassDefFoundError: org/tukaani/xz/XZInputStream
> at
> org.apache.commons.compress.compressors.CompressorStreamFactory.createCompressorInputStream(CompressorStreamFactory.java:120)
> at
> org.apache.tika.parser.pkg.ZipContainerDetector.detectCompressorFormat(ZipContainerDetector.java:95)
> at
> org.apache.tika.parser.pkg.ZipContainerDetector.detect(ZipContainerDetector.java:81)
> at org.apache.tika.detect.CompositeDetector.detect(CompositeDetector.java:61)
> at
> com.lookout.mimetype.TikaResourceMetadataFactory.createMetadata(TikaResourceMetadataFactory.java:166)
> at
> com.lookout.mimetype.TikaResourceMetadataFactory.createMetadata(TikaResourceMetadataFactory.java:112)
> (...)
> Caused by: java.lang.ClassNotFoundException: org.tukaani.xz.XZInputStream
> at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
> at java.security.AccessController.doPrivileged(Native Method)
> at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
> at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
> at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
> at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
> {code}
> The appropriate approach is to see if the classes exist before trying to use
> them. If they fail, then XZ is not supported and
> {{ZipContainerDetector.detect}} will not support XZ files.
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira