FindBugs отлавливает так называемые bug patterns - т.e. конструкции в коде, которые, скорее всего, являются ошибкой. Причем, для ее работы не обязательно иметь исходный код приложения - на самом деле она выполняет анализ байт-кода, используя для этих целей библиотечку Apache BCEL (ByteCode Engineering Library), которая уже упоминалась в этом сообщении. Таким образом, можно даже сторонние JARы проанализировать на наличие ошибок - FindBugs может обрабатывать JAR-, ZIP-файлы, и, конечно, class-файлы.
Установка сей тулзы подробно описана здесь. Я устанавливал FindBugs таким образом: скачал findbugs-1.3.8.zip c SourceForge.net, разархивировал его в каталог D:\tools\findbugs-1.3.8, установил переменную среды FINDBUGS_HOME=D:\tools\findbugs-1.3.8.
Далее мы разберем работу с FindBugs c использованием Ant. Кстати, у FindBugs есть также плагин к Eclipse. Но поскольку я являюсь сторонником использования командной строки (и особенно люблю Ant =) ), то именно совместное использование Ant & FindBugs - предмет данного поста.
FindBugs довольно требователен к памяти - в руководстве на сайте программы еще в первой главе отмечают, что для работы FindBugs потребуется минимум полгигабайта оператиной памяти, а лучше больше, конечно. При первых запусках на моей машине FindBugs выбрасывал исключение java.lang.OutOfMemoryError до тех пор, пока я не увеличил объем памяти, доступной JVM до 512Mb. В команде <findbugs> (о ней речь пойдет ниже) есть параметр jvmargs, который, как понятно из названия, содержит параметры, передаваемые JVM. Установив jvmargs="-Xmx512M" я избавился от java.lang.OutOfMemoryError.
Далее предполагается, что Ant установлен в каталог ANT_HOME, а FindBugs установлен в каталог FINDBUGS_HOME. Как я уже говорил, у меня на компьютере установлена переменная среды FINDBUGS_HOME=D:\tools\findbugs-1.3.8. Первым делом
<taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask"/> |
Рассмотрим параметры команды <findbugs> (в таблице ниже перечислены не все параметры, а только самые важные, на мой взгляд):
Параметр | Описание | Обязательный |
class | Дочерний элемент, указывающий, что именно анализировать. Должен содержать атрибут location, в котором указывается путь к анализируемому объекту. Это может быть директория, JAR или ZIP файл, class-файл. Тэг <findbugs> может содержать несколько дочерних элементов <class>. Пример:
| Да |
auxClasspath | Дочерний элемент, содержащий библиотеки, которые используются в анализируемом коде, но которые пользователь не будет анализировать. Этот элемент объявляется так же, как и classpath в команде <java>. Пример:<auxClasspath refid="main.classpath"/>- здесь идет ссылка на main.classpath, который ранее объявлен в файле сборки. Например, он может быть объявлен следующим образом:
| Нет |
home | Этот атрибут должен содержать имя каталога, где находится FindBugs. Пример: <findbugs home="${findbugs.home.dir}"> | Да |
reportLevel | Этот атрибут определяет уровень ошибок, которые выводятся в файл результатов. Есть три уровня:
<findbugs reportLevel="low"> | Нет |
output | Этот атрибут определяет формат файла отчета. Принимает следующие значения:
Пример: <findbugs output="xml:withMessages"> | Нет |
outputFile | Этот атрибут определяет имя файла отчета. Пример: <findbugs outputFile="${reports.file}"> | Нет |
jvmargs | Этот атрибут определяет параметры, передаваемые JVM. Чаще всего для анализа проектов следует увеличить память, доступную JVM. Делается это с помощью параметра -Xmx, пример: <findbugs jvmargs="-Xmx512M"> | Нет |
failOnError | Этот логический атрибут определяет, следует ли останавливать процесс сборки, если в при проверке обнаружены ошибки. Принимает значения true/false, по умолчанию false | Нет |
errorProperty | Этот атрибут определяет имя свойства, которое будет установлено в true, если при проверке будут обнаружены ошибки. Пример: <findbugs errorProperty="errors.present"> | Нет |
warningsProperty | Этот атрибут определяет имя свойства, которое будет установлено в true, если при проверке будут сгенерированы предупреждения. Пример: <findbugs warningsProperty="warnings.present"> | Нет |
Остальные параметры можно посмотреть здесь.
Теперь напишем цель для файла сборки, которая будет проверять наш (а может быть, и не наш) код на наличие ошибок.
<target name="findbugs" depends="compile"> |
После прогона FindBugs по коду одного из проектов (который писал не я =))) ) командой
> ant findbugs
были получены, например, следующие сообщения (всего получено сообщений 261):
Class defines clone() but doesn't implement Cloneable
May expose internal representation by returning reference to mutable object
Comparison of String objects using == or !=
Class defines compareTo(...) and uses Object.equals()
int division result cast to double or float
clone method does not call super.clone()
Method concatenates strings using + in a loop
Unread field
+ куча сообщений по поводу неосовобождения ресурсов после их использования (незакрытые java.sql.PreparedStatement, java.sql.ResultSet и т.п.).
FindBugs имеет удобный графический интерфейс для просмотра файла отчета. На Windows для запуска GUI можно запустить файл FINDBUGS_HOME\bin\findbugs.bat, или выполнить команду
java [JVM arguments] -jar $FINDBUGS_HOME/lib/findbugs.jar options...
Просмотр ошибок в GUI выглядит следующим образом:
В общем, после такой проверки, я предложил использовать FindBugs в нашем стандартном цикле разработки на каждой девелоперской машине. Каждый девелопер перед коммитом своих изменений в SVN обязан проверить свой код с помощью FindBugs и исправить конструкции в коде, на которые FindBugs ругается. Мое предложение было принято, и я ожидаю, что качество кода в наших проектах повысится благодаря использованию этого инструмента.