Статьи

Определение папок проекта для набора проектов

Цель этой статьи — развить некоторые из моих работ с превосходным модулем детектора мертвого кода Джеретана Виленга для NetBeans.

Вы можете прочитать об этом здесь: https://blogs.oracle.com/geertjan/entry/dead_code_detection_for_all .

Плагин основан на библиотеке Dead Code Detector от Emeric Vernat. Эту библиотеку можно найти здесь: https://java.net/projects/dcd/pages/Home .

Когда я приближался к выпуску приложения на платформе NetBeans, над которым я работал, я понял, что мои модули, вероятно, были полны кода, который был заменен, устарел или просто не использовался. Отвечая на мой запрос на форуме NetBeans, Гертьян не только написал записи в блоге о библиотеке, но и создал для нее плагин.

Эта проблема

Источник для плагина Geertjan легко доступен здесь: https://java.net/projects/nb-api-samples/sources/api-samples/show/versions/7.3/misc/NB-DCD Плагин работает, собирая проект папки всех выбранных проектов и добавление их в каталоги для сканирования с помощью Dead Code Detector:

public final class DetectDeadCodeAction implements ActionListener {
    private final List context;
    public DetectDeadCodeAction(List<Project> context) {
        this.context = context;
    }
    @Override
    public void actionPerformed(ActionEvent ev) {
        List directories = new ArrayList<File>();
        for (Project project : context) {
            directories.add(FileUtil.toFile(project.getProjectDirectory()));
        }
        // Call the Dead Code Detector with the list of directories.
    }
}

Работая с проектом платформы NetBeans, я в основном заинтересован в двух видах проектов; модули и комплекты. Вышеупомянутый подход работает в большинстве случаев, когда все модули для пакета находятся в каталоге пакета:

  • / SuiteA / ModuleA
  • / SuiteA / moduleB
  • / SuiteA / moduleC

При добавлении каталога / suiteA в каталоги для сканирования, каталоги для модулей A, B и C также сканируются.

Но что происходит, когда некоторые из ваших модулей находятся в другом каталоге?

  • / SuiteA / MODULEX
  • / Некоторые / другие / папки / moduleY
  • / Пока / другой / папка / moduleZ

Простое добавление / suiteA подберет модуль X, но модули Y и Z не будут сканироваться. Наборы проектов NetBeans могут включать в себя модули, которые находятся в других местах, поэтому необходимо изменить действие, чтобы сделать несколько вещей. Во-первых, нам нужно определить, является ли проект пакетом. Если это пакет, нам нужно найти все модули для пакета и добавить их каталоги для сканирования.

Это люкс?

Возможно, есть и другие способы сделать это, но решение, которое я в итоге реализовал, смотрит на файл project.xml. Обычно можно предположить, что файл project.xml действителен и правильно сформирован, если пользователь может загрузить и выбрать проект в среде IDE.

Вот как выглядит файл project.xml:

<project xmlns="http://www.netbeans.org/ns/project/1">
    <type>org.netbeans.modules.apisupport.project.suite</type>
    <configuration>
        <data xmlns="http://www.netbeans.org/ns/nb-module-suite-project/1">
            <name>DISPLAY NAME OF SUITE</name>
        </data>
    </configuration>
</project>

Поэтому, если тип проекта «org.netbeans.module.apisupport.project.suite», мы определили набор проектов.

public static final String SUITE = "<type>org.netbeans.modules.apisupport.project.suite</type>";

public boolean isProjectSuite(final Project project) {
    boolean returnValue = false;
    final FileObject projectDir = project.getProjectDirectory();
    final FileObject projectXml = projectDir.getFileObject(
            "nbproject/project.xml");
    if (projectXml != null) {
        try {
            final InputStream inStream = projectXml.getInputStream();
            final String xmlData = IOUtils.toString(inStream, "UTF-8");
            IOUtils.closeQuietly(inStream);
            returnValue = xmlData.contains(SUITE);
        } catch (IOException ioEx) {
            Exceptions.printStackTrace(ioEx);
        }
    }
    return returnValue;
}

Код просто удостоверяется, что project.xml существует, считывает весь файл в строку (с помощью пакета ввода-вывода Apache Commons) и проверяет, что тип действительно является набором. В качестве альтернативы, мы могли бы загрузить его, используя библиотеки DOM, и искать элемент <type> через XPath или что-то еще, но в этом случае это казалось излишним.

Каталоги модулей для A Suite

Итак, как только проект определен как набор, как мы определяем, где каждый из модулей живет? Ответ лежит в файле project.properties:

modules=\
    ${project.org.netbeans.moduleA}:\
    ${project.org.netbeans.moduleB}:\
    ${project.org.netbeans.moduleC}

project.org.netbeans.moduleA=moduleA
project.org.netbeans.moduleB=moduleB
project.org.netbeans.moduleC=../../other/folder/moduleC

Таким образом, каждый из ключей свойств, начинающихся с «project», имеет значения, которые представляют относительный путь к каталогу этого проекта. Отлично!

private Set<File> getProjectsForSuite(final Project project) {
    final Set<File> projectDirs = new HashSet<File>();
    final FileObject suiteDir = project.getProjectDirectory();
    final FileObject suiteProps = suiteDir.getFileObject(
            "nbproject/project.properties");
    if (suiteProps != null) {
        try {
            final InputStream inStream = suiteProps.getInputStream();
            final Properties props = new Properties();
            props.load(inStream);
            IOUtils.closeQuietly(inStream);           
            for (String key : props.stringPropertyNames()) {
                if (key.startsWith("project.")) {
                    final String relPath = props.getProperty(key);
                    final FileObject projectDir =
                            suiteDir.getFileObject(relPath);
                    if (projectDir != null) {
                        projectDirs.add(FileUtil.toFile(projectDir));
                    } else {
                        LOG.log(Level.INFO, "Null path for: {0}", relPath);
                    }
                }
            }
        } catch (IOException ioEx) {
            Exceptions.printStackTrace(ioEx);
        }
    }       
    return projectDirs;
}

В приведенном выше коде мы загружаем файл свойств в объект Properties. Мы перебираем все ключи и ищем те, которые начинаются с «проекта». Мы берем каталог набора и значение «проекта». ключи. FileObject имеет встроенную поддержку относительных путей, поэтому получение нового FileObject из каталога набора и значение ключа тривиально. Если каталог действительно существует, мы добавляем его в набор каталогов, возвращаемых методом.

Собираем все вместе

Вот модифицированная версия метода Geerjan actionPerformed:

public final class DetectDeadCodeAction implements ActionListener {
    private final List<Project> context;
    public DetectDeadCodeAction(List<Project> context) {
        this.context = context;
    }
    @Override
    public void actionPerformed(ActionEvent ev) {
        List<File> directories = new ArrayList<File>();
        for (Project project : context) {
            if (isProjectSuite(project)) {
                directories.addAll(getProjectsForSuite(project));
            } else {
                directories.add(FileUtil.toFile(project.getProjectDirectory()));
            }
        }
        // Call the Dead Code Detector with the list of directories.
    }
}

Идти дальше

Детектор мертвого кода не работает с исходными файлами. Это работает против скомпилированного кода; JAR-файлы и файлы классов. Возможно, что ваш каталог build / target может не существовать в той же иерархии каталогов, что и исходный каталог. Может быть случай использования для указания каталога build / target для проекта. Как Ant, так и Maven могут указывать расположение своих исходных каталогов и каталогов build / target, так что может быть случай, чтобы удовлетворить эти типы проектов. В настоящее время в проектах Ant и Maven обычно есть каталоги как source, так и build / target, расположенные в подкаталоге проекта, поэтому в большинстве случаев действие должно работать как есть.

Dead Code Detector — это увлекательный проект, который работает (и быстро), чтобы найти потенциально мертвый код в ваших проектах. Поздравляем Emeric за его работу над этим проектом и поздравляем Geertjan за быструю разработку плагина, который прекрасно интегрируется с IDE!