[ 
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

Reply via email to