2016-11-25 4 views
3

Как я могу программно получить все зависимости модуля Maven вне среды выполнения Maven?Maven: получить все зависимости программно

До сих пор у меня есть:

с помощью Maven-ядра:

Path pomPath = ...; 
MavenXpp3Reader reader = new MavenXpp3Reader(); 
try (InputStream is = Files.newInputStream(pomPath)) { 
    Model model = reader.read(is); 
    this.mavenProject = new MavenProject(model); 
} 

и через jcabi-эфир:

File localRepo = Paths.get(System.getProperty("user.home"), ".m2").toFile(); 
new Classpath(mavenProject, localRepo, "runtime") 

Является ли это вообще правильно до сих пор?

Сейчас вопрос в том, что я получаю NullPointerException:

Caused by: java.lang.NullPointerException 
    at com.jcabi.aether.Aether.mrepos(Aether.java:197) 
    at com.jcabi.aether.Aether.<init>(Aether.java:140) 
    at com.jcabi.aether.Classpath.<init>(Classpath.java:125) 

так mavenProject.getRemoteProjectRepositories() возвращает нуль.

Как я могу инициализировать MavenProject, чтобы он содержал настроенные удаленные репозитории, которые также учитывали файл settings.xml (зеркала, прокси, репозитории и т. Д.)?

+0

Я не думаю, что это происходит в правильном направлении. Взгляните на ['dependency: get'] (http://maven.apache.org/plugins/maven-dependency-plugin/get-mojo.html) вместо – janos

+0

Если у вас нет файла POM и только есть координаты, вы можете посмотреть на Эфир. Чтобы получить прямые зависимости от эфира, [вы можете сослаться на этот мой ответ] (http://stackoverflow.com/questions/39638138/find-all-direct-dependencies-of-an-artifact-on-maven-central) , Если у вас есть POM, то использование 'dependency: get -Dtransitive = false' будет получать прямые зависимости намного проще. Взгляните на [Invoker API] (http://maven.apache.org/shared/maven-invoker/) – Tunaki

+0

Чтобы уточнить: у меня есть файл POM, но код выполняется вне выполнения Maven. Я хочу заполнить URLClassLoader URL-адресами зависимостей в локальном репо (которые, возможно, придется сначала загрузить из удаленного репо). Я не вижу, как плагин поможет мне ... – Puce

ответ

4

Вне плагина Maven способ работы с артефактами осуществляется через эфир. У команды есть образец проекта для получения транзитивных зависимостей данного артефакта под названием ResolveTransitiveDependencies. Если у вас есть зависимости Эфира настроенные (like shown here), вы можете просто:

public static void main(final String[] args) throws Exception { 
    DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator(); 
    RepositorySystem system = newRepositorySystem(locator); 
    RepositorySystemSession session = newSession(system); 

    RemoteRepository central = new RemoteRepository.Builder("central", "default", "http://repo1.maven.org/maven2/").build(); 

    Artifact artifact = new DefaultArtifact("group.id:artifact.id:version"); 

    CollectRequest collectRequest = new CollectRequest(new Dependency(artifact, JavaScopes.COMPILE), Arrays.asList(central)); 
    DependencyFilter filter = DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE); 
    DependencyRequest request = new DependencyRequest(collectRequest, filter); 
    DependencyResult result = system.resolveDependencies(session, request); 

    for (ArtifactResult artifactResult : result.getArtifactResults()) { 
     System.out.println(artifactResult.getArtifact().getFile()); 
    } 
} 

private static RepositorySystem newRepositorySystem(DefaultServiceLocator locator) { 
    locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class); 
    locator.addService(TransporterFactory.class, FileTransporterFactory.class); 
    locator.addService(TransporterFactory.class, HttpTransporterFactory.class); 
    return locator.getService(RepositorySystem.class); 
} 

private static RepositorySystemSession newSession(RepositorySystem system) { 
    DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); 
    LocalRepository localRepo = new LocalRepository("target/local-repo"); 
    session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo)); 
    return session; 
} 

Это загрузит артефакты и поместить их в "target/local-repo".

Обратите внимание, что вы можете настроить прокси и зеркала с помощью DefaultProxySelector и DefaultMirrorSelector в системном сеансе. Можно было бы прочитать файл настройки Maven и использовать его для заполнения сессии, но все становится очень некрасиво очень быстро ...


Если вы хотите, тесную связь с самой Maven, потому что у вас есть доступ к POM для обработки и принятия во внимание настроек, гораздо проще напрямую вызывать Maven программно. В этом случае вам интересен путь каждой зависимости, включая транзитивные зависимости, заданного POM-файла. Для этого цель dependency:list вместе с установкой outputAbsoluteArtifactFilename на true даст (почти) именно это.

Чтобы программно использовать Maven, можно использовать Invoker API. Добавление зависимости к проекту:

<dependency> 
    <groupId>org.apache.maven.shared</groupId> 
    <artifactId>maven-invoker</artifactId> 
    <version>2.2</version> 
</dependency> 

вы можете иметь:

InvocationRequest request = new DefaultInvocationRequest(); 
request.setPomFile(new File(pomPath)); 
request.setGoals(Arrays.asList("dependency:list")); 
Properties properties = new Properties(); 
properties.setProperty("outputFile", "dependencies.txt"); // redirect output to a file 
properties.setProperty("outputAbsoluteArtifactFilename", "true"); // with paths 
properties.setProperty("includeScope", "runtime"); // only runtime (scope compile + runtime) 
// if only interested in scope runtime, you may replace with excludeScope = compile 
request.setProperties(properties); 

Invoker invoker = new DefaultInvoker(); 
// the Maven home can be omitted if the "maven.home" system property is set 
invoker.setMavenHome(new File("/path/to/maven/home")); 
invoker.setOutputHandler(null); // not interested in Maven output itself 
InvocationResult result = invoker.execute(request); 
if (result.getExitCode() != 0) { 
    throw new IllegalStateException("Build failed."); 
} 

Pattern pattern = Pattern.compile("(?:compile|runtime):(.*)"); 
try (BufferedReader reader = Files.newBufferedReader(Paths.get("dependencies.txt"))) { 
    while (!"The following files have been resolved:".equals(reader.readLine())); 
    String line; 
    while ((line = reader.readLine()) != null && !line.isEmpty()) { 
     Matcher matcher = pattern.matcher(line); 
     if (matcher.find()) { 
      // group 1 contains the path to the file 
      System.out.println(matcher.group(1)); 
     } 
    } 
} 

Это создает запрос вызова, который содержит: цели для вызова и свойства системы, так же, как вы бы запустить mvn dependency:list -Dprop=value на командная строка. Путь к используемым настройкам будет по умолчанию равным стандарту "${user.home}/settings.xml", но также можно указать путь к настройкам с помощью request.setUserSettingsFile(...) и request.setGlobalSettingsFile(...). Invoker должен быть установлен для дома Maven (т. Е. Установочного каталога), но только если системное свойство "maven.home" не установлено.

Результат вызова dependency:list перенаправлен на файл, который позже обрабатывается после обработки. Выход этой цели состоит из списка зависимостей в формате (классификатор может отсутствовать, если их нет):

group.id:artifact.id:type[:classifier]:version:scope:pathname 

Существует не способ вывода только путь файла устраненного артефакта , и тот факт, что классификатор может отсутствовать, усложняет разбор бит (мы не можем разделить на : с пределом, так как путь может содержать : ...). Во-первых, разрешенные артефакты находятся ниже строки "The following files have been resolved:" в выходном файле, тогда, поскольку требуемый объем составляет только compile или runtime, мы можем получить путь к файлу артефакта с простым регулярным выражением, которое занимает все, что после compile: или runtime: , Затем этот путь можно использовать непосредственно как new File.

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

+0

Спасибо, это помогло мне реализовать первую версию с поддержкой настроек. – Puce

Смежные вопросы