Skip to content

Instantly share code, notes, and snippets.

@KengoTODA
Created Oct 28, 2012
Embed
What would you like to do?
A way to build FindBugs plugin with Maven3

Use findbugs-slf4j project as an example.

How to include meta file as resource

To build FindBugs plugin, we have to include meta files into package file. But we cannot put meta files into src/main/resources, because it breaks Unit testing like this.

java.lang.ExceptionInInitializerError
        at edu.umd.cs.findbugs.DetectorFactoryCollection.getCoreResource(DetectorFactoryCollection.java:360)
        at edu.umd.cs.findbugs.SystemProperties.loadPropertiesFromConfigFile(SystemProperties.java:72)
        at edu.umd.cs.findbugs.SystemProperties.<clinit>(SystemProperties.java:55)
        at edu.umd.cs.findbugs.visitclass.AnnotationVisitor.<clinit>(AnnotationVisitor.java:64)
        at jp.skypencil.findbugs.simple.OriginalDetectorTest.testNopIsNotBug(OriginalDetectorTest.java:14)
        ... (omitted)
Caused by: java.lang.IllegalStateException: Unable to load core plugin
        at edu.umd.cs.findbugs.PluginLoader.loadCorePlugin(PluginLoader.java:1423)
        at edu.umd.cs.findbugs.PluginLoader.loadInitialPlugins(PluginLoader.java:1373)
        at edu.umd.cs.findbugs.PluginLoader.<clinit>(PluginLoader.java:156)
        ... 34 more
Caused by: edu.umd.cs.findbugs.PluginDoesntContainMetadataException:
Core pluginfindbugs-2.0.1.jar doesn't contain findbugs.xml; got
.../target/classes/findbugs.xml
from sun.misc.Launcher$AppClassLoader[.../target/surefire/surefirebooter4183093093081081854.jar]
        at edu.umd.cs.findbugs.PluginLoader.getPluginDescriptor(PluginLoader.java:1112)
        at edu.umd.cs.findbugs.PluginLoader.init(PluginLoader.java:611)
        at edu.umd.cs.findbugs.PluginLoader.<init>(PluginLoader.java:357)
        at edu.umd.cs.findbugs.PluginLoader.loadCorePlugin(PluginLoader.java:1419)
        ... 36 more

You can use maven-resources-plugin as a simple workaround. Just copy meta files after unit testing into ${project.build.outputDirectory}. I learned this way at "How to build FindBugs plugin with Maven" thread in findbugs-discuss ML. Thanks for Philippe Arteau!

Do not forget to execute clean before testing to delete copied meta files.

      <plugin>
        <!--
          Copy meta files to default outputDirectory at "prepare-package" phase.
          Note: You should execute "clean" phase before you execute "test" phase.
        -->
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.6</version>
        <executions>
          <execution>
            <phase>prepare-package</phase>
            <goals>
              <goal>copy-resources</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.outputDirectory}</outputDirectory>
              <resources>
                <resource>
                  <directory>src/main/meta</directory>
                </resource>
              </resources>
            </configuration>
          </execution>
        </executions>
      </plugin>

How to test FindBugs plugin

FindBugs has some annotation to support testing, but I cannot find good document which explains how to use it. So I create a simple structure to ensure feature.

Create simple classes to reproduce required situation, and execute our plugin to check their class files. Then we can parse findbugsXml.xml to verify our plugin. It's a very simple way but enough powerful, isn't it?

We can use compile phase to generate class files, pre-integration-test phase to execute plugin and integration-test phase to test.

How to parse findbugsXml.xml

To count bugs, we can use bugCount attribute of FileStats element.

DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse("target/findbugsXml.xml");
NodeList fileStats = doc.getElementsByTagName("FileStats");

for (int i = 0; i < fileStats.getLength(); ++i) {
    Node node = fileStats.item(i);
    NamedNodeMap attr = node.getAttributes();
    if (attr.getNamedItem("path").getNodeValue().equals(filePath)) {
        final String bugCount = attr.getNamedItem("bugCount").getNodeValue();
        final String message;
        if (expectedBugs == 0) {
            message = filePath + " should have no bug";
        } else {
            message = filePath + " should have " + expectedBugs + " bugs";
        }

        assertThat(message, bugCount, is(Integer.toString(expectedBugs)));
        return;
    }
}

fail("Result of " + filePath + " not found");

If you need type of bug, you can use type attribute of BugInstance element.

@wliyongfeng
Copy link

wliyongfeng commented May 27, 2013

Hi, I encountered the java.lang.ExceptionInInitializerError when I execute Junit test(the test process in mvn clean install is ok).

Sometimes it's okay, but many times it will throw exception, do you have any experience with this?
Thank you!

@wliyongfeng
Copy link

wliyongfeng commented May 27, 2013

Oh, I think I got it. I need to delete the metedata files under the directory target/classes.

Thanks all the same.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment