Если вам действительно нужно добиться этого с помощью maven или сценариев, вот как у меня это работает.
На основе подхода, предложенного другим answer в Stackoverflow, я реализовал следующий простой класс:
package com.sample;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Scanner;
import org.clapper.util.classutil.ClassFilter;
import org.clapper.util.classutil.ClassFinder;
import org.clapper.util.classutil.ClassInfo;
public class MainScan {
public static void main(String[] args) throws Exception {
if (args.length < 2) {
System.out.println("Missing options");
System.exit(-1);
}
System.out.println("Filtering by: " + args[1]);
ClassFinder finder = new ClassFinder();
finder.addClassPath();
loadClasspath(finder, args[0]);
ClassFilter filter = new ImplementInterfaceFilter(args[1]);
// you could also use as a filter: new
// SubclassClassFilter(AbstractFileFilter.class);
// or make a concatenation of filters using an AndClassFilter
Collection<ClassInfo> foundClasses = new ArrayList<ClassInfo>();
finder.findClasses(foundClasses, filter);
if (foundClasses.size() > 0) {
for (ClassInfo classInfo : foundClasses) {
System.out.println("- " + classInfo.getClassName());
// consider also using classInfo.getClassLocation() to get the
// jar file providing it
}
} else {
System.out.println("No matches found.");
}
}
static void loadClasspath(ClassFinder finder, String file) throws IOException {
Scanner s = new Scanner(new File(file));
s.useDelimiter(File.pathSeparator);
try {
while (s.hasNext()) {
finder.add(new File(s.next()));
}
} finally {
s.close();
}
}
static class ImplementInterfaceFilter implements ClassFilter {
private String interfaceName;
public <T> ImplementInterfaceFilter(String name) {
this.interfaceName = name;
}
public boolean accept(ClassInfo info, ClassFinder finder) {
for (String i : info.getInterfaces()) {
if (i.endsWith(this.interfaceName)) {
return true;
}
}
return false;
}
}
}
Обратите внимание, что класс находится в пакете com.sample
, но его, очевидно, можно переместить в другой пакет. Основной метод ожидает два параметра: файл пути к классам и имя интерфейса, затем он добавит путь к классам в средство поиска путей к классам и просканирует его в поисках классов, реализующих предоставленное имя интерфейса (с помощью настраиваемого фильтра, также предоставленного выше). Оба варианта будут предоставлены Maven во время выполнения следующим образом:
Я использовал эту библиотеку для сканирования пути к классам, поэтому, как предлагается на официальной странице, нам нужно добавить настраиваемый репозиторий для нашего POM:
<repositories>
<repository>
<releases>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</releases>
<id>clapper-org-maven-repo</id>
<name>org.clapper Maven Repo</name>
<url>http://maven.clapper.org/</url>
<layout>default</layout>
</repository>
</repositories>
И необходимая зависимость:
<dependencies>
...
<dependency>
<groupId>org.clapper</groupId>
<artifactId>javautil</artifactId>
<version>3.1.2</version>
</dependency>
...
</dependencies>
Затем нам просто нужно настроить следующее в нашей сборке Maven:
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>build-classpath</goal>
</goals>
<configuration>
<outputFile>${project.build.directory}/classpath.txt</outputFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<phase>validate</phase>
<goals>
<goal>java</goal>
</goals>
<configuration>
<mainClass>com.sample.MainScan</mainClass>
<arguments>
<argument>${project.build.directory}/classpath.txt</argument>
<argument>${interfaceName}</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
В основном мы настраиваем подключаемый модуль Maven Dependency для записи полного пути к классам сборки Maven в файл, а затем используем подключаемый модуль Exec Maven для выполнения нашего настраиваемого основного Java-файла, передавая ему файл пути к классам и параметр ${interfaceName}
. Выполнение обоих плагинов связано с validate
фазой: нам не нужно выполнять полную сборку maven, мы просто вызовем одну из ее первых фаз для этой задачи.
Таким образом, мы можем вызвать сборку maven следующим образом:
mvn validate -DinterfaceName=Serializable -q
И получите следующий результат:
Filtering by: Serializable
- org.apache.commons.io.ByteOrderMark
- org.apache.commons.io.comparator.CompositeFileComparator
- org.apache.commons.io.comparator.DefaultFileComparator
...
Команда Maven напрямую вызовет нашу соответствующую фазу validate
, используя параметр -q
(довольно), чтобы пропустить любой журнал сборки maven и просто получить интересующий нас результат. Более того, мы можем затем динамически передавать желаемый интерфейс с помощью параметра -DinterfaceName=<value_here>
. Он передаст значение подключаемому модулю Exec Maven и, следовательно, основному компоненту Java, указанному выше.
В соответствии с дополнительными потребностями (создание сценариев, вывод, формат и т. Д.) Основная часть Java может быть легко адаптирована. Более того, плагины, зависимости, конфигурация репозиториев также могут быть перемещены в профиль Maven, чтобы сделать его более чистым и организованным.
Последнее замечание: если вы измените пакет основного Java выше, не забудьте соответствующим образом изменить конфигурацию подключаемого модуля Exec Maven (элемент mainClass
).
Итак, вернемся к вашим вопросам:
- Можно ли с помощью команды mvn запросить, какие классы в каком пакете реализуют выбранный интерфейс? Да, применив подход, описанный выше.
- Или даже больше - чтобы найти классы и пакеты в сборке приложения CLASSPATH, который является подклассами или суперклассами выбранного класса? Да, посмотрите SubclassClassFilter из той же библиотеки, соответственно измените основную часть выше, и вы получите ее.
- Существуют ли подключаемые модули, подходящие для моих нужд? Мне не удалось их найти, но приведенный выше код можно легко преобразовать в новый подключаемый модуль Maven. В противном случае описанный здесь подход представляет собой сочетание кода Java и использования существующих плагинов Maven, что в любом случае может удовлетворить ваши потребности.
person
A_Di-Matteo
schedule
01.01.2016