How to run FindBugs off of Ivy downloaded JARs

448 views Asked by At

I've got Ant and Ivy setup so that I can use Ivy downloaded JARs to run PMD. Trying the same with FindBugs, setting the findbugs.home Ant property to ivy-jars/findbugs, where the Ivy JARs go. I initially got the error that it couldn't find the JAR files under the ${findbugs.home}/lib directory. I fixed that by changing Ivy to download the JAR files into ivy-jars/findbugs/lib. However, this gave rise to the new error:

Executing findbugs FindBugsTask from ant task
Running FindBugs...
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/bcel/classfile/ClassFormatException
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
    at java.lang.Class.getMethod0(Class.java:3018)
    at java.lang.Class.getMethod(Class.java:1784)
    at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526)
Caused by: java.lang.ClassNotFoundException: org.apache.bcel.classfile.ClassFormatException
    at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 7 more  
2

There are 2 answers

0
Matthew Cline On

This turns out to be caused by three problems:

  1. I retrieved the JAR files using symlink="true". FindBugs dereferences the symlink to findbugs.jar and looks for all of its other JAR files under the same directory, but the way Ivy structures its cache only the findbugs.jar is in that directory. This can be fixed easily enough by not using symlinks.
  2. FindBugs wants its JAR files to sometimes have the filename format [artifact].[ext] and sometimes have the format [artifact]-[revision].[ext], which can be solved by doing <ivy:retrieve> two times with different pattern values.
  3. FindBugs wants the file name for the BCEL JAR file to be exactly bcel-6.0-SNAPSHOT.jar rather than bcel-findbugs.jar or bcel-findbugs-6.0.jar; this can be fixed with a symbolic link.

I consider this to just be a workaround, rather than a true solution, since #2 and #3 can't be how FindBugs is intended to be used under Ivy. So if anyone knows the right way to do it, please provide a better answer.

0
Mark Slater On

Contrary to the documentation, the home attribute is not required. Instead, you can provide a nested classpath element, which can be any path-like structure.

The following Ant target works for me:

<target name="findbugs" description="Run findbugs on the code">
    <ivy:retrieve/>
    <ivy:cachepath pathid="findbugs.classpath" conf="findbugs"/>
    <taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask" classpathref="findbugs.classpath"/>
    <findbugs>
        <classpath refid="findbugs.classpath"/>
        <class location="my-analysis-target.jar"/>
    </findbugs>
</target>

Where my ivy.xml is:

<ivy-module version="2.0">
    <info organisation="meh" module="meh"/>
    <configurations defaultconfmapping="findbugs->default">
        <conf name="findbugs"/>
    </configurations>
    <dependencies>
        <dependency org="com.google.code.findbugs" name="findbugs" rev="3.0.1" conf="findbugs"/>
    </dependencies>
</ivy-module>