Статьи

Среда проверки

Одним из интересных инструментов, о которых я узнал на JavaOne 2012, является The Checker Framework . На одной из веб-страниц Checker Framework утверждается, что Checker Framework «улучшает систему типов Java, делая ее более мощной и полезной,» позволяя разработчикам программного обеспечения «обнаруживать и предотвращать ошибки в своих программах Java». Один из способов взглянуть на Checker Framework — это реализация того, что JSR 305 («Аннотации для обнаружения дефектов программного обеспечения») могла бы не попасть в стадию бездействия .

Цель JSR 308 («Аннотации в типах Java») состоит в том, чтобы «расширить синтаксис аннотаций Java, чтобы разрешить аннотации в любом случае типа». Как только JSR 308 будет утвержден и станет частью языка программирования Java, аннотации будут разрешены там, где они в настоящее время не разрешены. Хотя JSR 308 все еще находится на этапе раннего предварительного просмотра 2 , Checker Framework позволяет разработчику включать закомментированный код аннотации в тех местах, которые в настоящее время не разрешены до тех пор, пока не станут доступны в JSR 308. Здесь важно отметить, что JSR 308 делает аннотации только в более общем виде. доступный (указывает больше типов исходного кода, к которому они могут быть применены) и не указывает никаких новых аннотаций.

Для Checker Framework требуется Java SE 6 или более поздняя версия. Среду Checker Framework можно загрузить в виде одного ZIP-файла по адресу http://types.cs.washington.edu/checker-framework/current/checkers.zip . Загруженный файл может быть разархивирован в платформу проверки каталогов, а затем может быть установлена ​​переменная среды CHECKERS, указывающая на подкаталог этого расширенного каталога «checkers». Например, если файл checkers.zip разархивирован в C: \ checker-framework, для переменной среды CHECKERS должно быть установлено C: \ checker-framework \ checkers.

Когда Checkers Framework checkers.zip был загружен, расширен и указан переменной среды CHECKERS, пришло время попробовать Checker Framework. Далее показан «длинный путь» запуска Checker Framework, который используется с тегом -version для проверки того, что Checker Framework применяется:

Windows

java -Xbootclasspath/p:%CHECKERS%/binary/jsr308-all.jar -jar %CHECKERS%/binary/jsr308-all.jar -version 

Linux

java -Xbootclasspath/p:$CHECKERS/binary/jsr308-all.jar -jar $CHECKERS/binary/jsr308-all.jar -version 

Вышеуказанное должно привести к выводу, который будет выглядеть примерно так, как показано на следующем снимке экрана.

Установленная Checker Framework теперь может быть применена для компиляции кода. В следующем листинге кода показан простой класс, который указывает, что аргумент метода не должен быть нулевым с помощью аннотации checkers.nullness.quals.NonNull ( @NonNull ).

Пример использования Checker Framework @NonNull

package dustin.examples;

import checkers.nullness.quals.NonNull;
import static java.lang.System.out;

public class CheckersDemo
{
   public void printNonNullToString(@NonNull final Object object)
   {
      out.println(object.toString());
   }

   public static void main(final String[] arguments)
   {
      final CheckersDemo me = new CheckersDemo();
      final String nullStr = null;
      me.printNonNullToString(nullStr);
   }
}

Приведенный выше листинг кода показывает, что в метод передается значение NULL с аргументом, аннотированным @NonNull. NetBeans 7.3 помечает это желтыми загогулинами и предупреждает, если наведен. Это показано на следующих снимках экрана.

Хотя NetBeans помечает нулевое значение параметра, помеченного аннотацией @NonNull, компилятор создает этот код без жалоб. Вот тут-то и вступает Checker Framework. Поскольку вводить длинную команду, которую я показывал ранее, очень сложно, я либо запускаю указанную выше команду со скриптом, либо устанавливаю псевдоним, как описано в инструкциях по установке Checker Framework . В этом случае я буду использовать псевдоним:

Настройка псевдонима командной строки Windows для проверки Java

doskey javachecker=java -Xbootclasspath/p:%CHECKERS%\binary\jsr308-all.jar -jar %CHECKERS%\binary\jsr308-all.jar $*

Настройка этого псевдонима и запуск его с флагом -version продемонстрирован на следующем снимке экрана.

Гораздо проще применить этот подход с набором псевдонимов. Это может быть использовано для компиляции рассматриваемого класса, как показано ниже (команда, использующая мой псевдоним ‘javachecker’ и изображение, показывающее результат).

javachecker -d classes src\dustin\examples\*.java

Приведенная выше команда демонстрирует, что я могу использовать обычные параметры javac, такие как -d, чтобы указать каталог назначения для скомпилированных файлов .class и передать исходные файлы Java для компиляции в обычном режиме. В этом примере также показано, что без указания процессора проверки для запуска в процессе компиляции дополнительная типизация @NotNull не применяется во время компиляции.

Прежде чем показать, как указать процессор для принудительного применения @NonNull во время компиляции, я хочу быстро продемонстрировать, что этот подход к компиляции будет по-прежнему сообщать о стандартных ошибках компилятора. Как раз для этого примера я переименовал переменную «nullStr», переданную интересующему методу в строке 17, в «nullStry», чтобы это было ошибкой компилятора. На следующих двух снимках экрана показано это изменение (и сообщенная ошибка компиляции NetBeans) и то, как подход компиляции Checker Framework также сообщает об ошибке javac.

Показав, что этот подход к компиляции нормально компилирует компилируемый код, нормально сообщает об ошибках компилятора и соответствующим образом показывает версию, пришло время применить его для более строгого применения типов. Я исправляю ошибку компилятора в своем коде, удаляя лишние «y», которые я добавил. Затем мне нужно передать -processor checkers.nullness.NullnessChecker в качестве дополнительного флага и аргумента процесса компиляции. Обратите внимание, что есть и другие процессоры, кроме NullnessChecker , но я использую NullnessChecker здесь для принудительного применения @NonNull во время компиляции.

Ниже показана команда вместе с окном вывода, демонстрирующее эту команду в действии. Обратите внимание, что процесс компиляции не может быть завершен, и сообщается об ошибке, связанной с нарушением типизации @NonNull.

javachecker -processor checkers.nullness.NullnessChecker -d classes src\dustin\examples\*.java 

В этом сообщении в блоге рассказывается о Checker Framework и показано, как быстро применить его для более строгого соблюдения типов в исходном коде Java. Здесь я сосредоточился только на одном типе более строгой типизации, но Checker Framework предоставляет другие встроенные проверки типов и поддерживает возможность написания пользовательских проверок принудительного исполнения типов.