A blog about software development and other software related matters

Blog Archive

Saturday, September 27, 2008

Custom findbugs detectors and maven

Iv been writing a custom find bugs detector during the weekend, the bug that this detector has to detect is String.getBytes() usages, default system encoding is used when converting the char sequence into bytes which can make it work on one machine and fail on another (use String.getBytes(charsetName) instead).
The writing of the detector was not straight forward but im not going to focus on this issue (see this and this), instead id like to focus on how to create a findbugs plugin by using maven and running it with maven findbugs plugin.
First here is the detector code:


package com.jdftm;

import java.text.DateFormat;
import java.util.Calendar;

import org.apache.bcel.generic.ObjectType;

import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.ba.*;
import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;

public class StringGetBytesDetector extends OpcodeStackDetector {

private BugReporter reporter;
private final ObjectType stringType = ObjectTypeFactory.getInstance("java.lang.String");
private final static String tBugType = "SGB_STRING_GET_BYTES";

public StringGetBytesDetector(BugReporter aReporter) {
reporter = aReporter;
new String("").getBytes();
}

@Override
public void sawOpcode(int seen) {
if (seen != INVOKEVIRTUAL) {// we are only interested in method calls
return;
}

try {
ObjectType tType = ObjectTypeFactory.getInstance(getClassConstantOperand());
if (!tType.subclassOf(stringType) ||
!getClassConstantOperand().equals("java/lang/String") ||
!getNameConstantOperand().equals("getBytes")) {
return;
}

reporter.reportBug(new BugInstance(this,tBugType, NORMAL_PRIORITY).addClassAndMethod(this).addCalledMethod(this).addSourceLine(this));
} catch (ClassNotFoundException e) {
AnalysisContext.reportMissingClass(e);
}
}
}

This class should reside in the src/main/java path of your maven module, findbugs requires another two files to be present in the plugin jar, findbugs.xml (contains bugs and detectors meta data):

<FindbugsPlugin>
<Detector class="com.jdftm.StringGetBytesDetector" speed="fast"/>
<BugPattern abbrev="SGB" type="SGB_STRING_GET_BYTES" category="CORRECTNESS"/>
</FindbugsPlugin>

And messages.xml (contains bug messages and detector description):

<MessageCollection>
<Detector class="com.jdftm.StringGetBytesDetector">
<Details>
<p>This detector warns about String.getBytes uages.</p>
</Details>
</Detector>
<BugPattern type="SGB_STRING_GET_BYTES">
<ShortDescription>Call getBytes on String instance</ShortDescription>
<LongDescription>Call getBytes on String instance</LongDescription>
<Details>Using String.getBytes is bad!</Details>
</BugPattern>
</MessageCollection>

Both files should reside in the src/main/resources path, the plugin also has the following dependencies:

<dependency>
<groupId>findbugs</groupId>
<artifactId>findbugs</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>org.apache</groupId>
<artifactId>bcel</artifactId>
<version>5.2</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.1>/version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm-tree</artifactId>
<version>3.</version>
</dependency>

The easiest way of getting them is by downloading findbugs distribution and deploying them from the lib folder into your favorite maven proxy (artifactory in my case).
All that is left is to deploy the plugin and to add it to your maven findbugs plugin configuration:

<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>2.0</version>
<configuration>
<effort>Max</effort>
<threshold>Low</threshold>
<xmlOutput>true</xmlOutput>
<debug>true</debug>
<pluginList>{artifact_path}/findstringtobyte-1.0.jar</pluginList>
</configuration>
</plugin>
</plugins>
</reporting>

Thats about all :)

* A small note:
The findbugs maven plugin has a bug in the 1.2.0 release that was fixed for the 1.2.1 & 2.0 snapshot versions, it prevent the use of custom detector which means that youll need to use one of the snapshots versions.

No comments: