2016-11-14 2 views
2

Я создал небольшую утилиту для обертывания MavenCli, которая генерирует новый проект Maven с использованием артефакта quickstart.Вызов MavenCli сбой в плагине Maven

При выполнении Util в качестве модульного теста он работает достаточно хорошо (просто генерирует пустой проект Maven).

Теперь я хочу интегрировать эту небольшую обертку в плагин Maven. Но когда я исполню харизмы (в рамках третьего проекта Maven), призывание MavenCli терпит неудачу с исключением:

[ERROR] Error executing Maven. 
[ERROR] java.util.NoSuchElementException 
    role: org.apache.maven.eventspy.internal.EventSpyDispatcher 
    roleHint: 
[ERROR] Caused by: null 

Util выглядит следующим образом:

public void createProject() { 
    final MavenCli cli = new MavenCli(); 
    System.setProperty("maven.multiModuleProjectDirectory", "/usr/share/maven"); 
    cli.doMain(new String[] { "archetype:generate", "-DgroupId=com.my.company", 
      "-DartifactId=hello-world", "-DarchetypeArtifactId=maven-archetype-quickstart", 
      "-DinteractiveMode=false" }, "/tmp", System.out, System.out); 
} 

соответствующей зависимости от Util:

<dependency> 
    <groupId>org.apache.maven</groupId> 
    <artifactId>maven-embedder</artifactId> 
    <version>3.3.9</version> 
</dependency> 
<dependency> 
    <groupId>org.apache.maven</groupId> 
    <artifactId>maven-core</artifactId> 
    <version>3.3.9</version> 
</dependency> 

код харизмы выглядит следующим образом:

@Mojo(name = "custommojo", requiresProject = false) 
public class CustomMojo extends AbstractMojo { 

    @Override 
    public void execute() throws MojoExecutionException, MojoFailureException { 
     Util.createProject(); 
    } 

} 

POM mojo включает в себя зависимости от соответствующих артефактов Maven (плагин-api, плагин-аннотация и т. Д.) И утилиты.

Третий проект, о котором я упоминал, представляет собой пустой проект «maven-quickstart», который имеет зависимость от проекта mojo и конфигурацию mojo для выполнения на этапе компиляции.

Я понятия не имею, почему это работает в контексте модульного теста, но не в контексте mojo.

Может ли кто-нибудь помочь?

ответ

3

Это проблема с загрузкой класса.

MavenCli попытается загрузить классы из контекстного загрузчика классов текущего потока. Внутри плагина Maven находится a special, restricted, classloader, который имеет доступ к:

  • собственные классы;
  • классы, используемые в блоке зависимостей;
  • экспортированные классы как часть возможного расширения сборки проекта;
  • экспортированные классы из основных и основных расширений Maven;
  • и имеет загрузчик bootstrap в качестве родительского.

Однако конкретный класс org.apache.maven.eventspy.internal.EventSpyDispatcher является частью ядра Maven, но it is not part of the exported APIs (пакет org.apache.maven.eventspy не указан в качестве exportedPackage). Поэтому плагин не может загрузить этот класс. Вот почему он работает в ваших тестах: вы не внутри плагина, поэтому classloader отличается и имеет доступ к этому классу.

Вы даже не сможете уйти с добавлением эксплицитно зависимости от maven-core для плагина: он будет потерян, поскольку он предположительно уже предоставлен.

Есть 2 решения здесь:

  • Не используйте API Maven Embedder внутри плагина, но Invoker API. Разница между ними заключается в том, что API Invoker запускает Maven в чистой среде, полностью отличной от текущей. Поскольку все начинается заново, у вас не будет проблемы с загрузкой.
  • Используйте библиотеку mojo-executor, которая обеспечивает простой способ вызова других Mojos из плагина Maven. Вы могли бы использовать его здесь, чтобы вызвать 0jojdb.
+0

Спасибо много - я переключился на INVOKER API, как предложено - и она работает очень хорошо. Примечание. До того, как я использовал API-интерфейс Embedder, я уже пытался использовать mojo-executor, но безуспешно, так как сложно выполнить весь жизненный цикл (например, «установить»). Mojo-executor работает для «archetype: generate», но также сложно настроить при попытке вызвать mojo для другого проекта (особенно, когда этот другой проект полностью выходит за рамки текущей сборки) –

+0

Фактически можно обрабатывать проблему загрузки классов и использовать «MavenCli», см. мой ответ. –

0

Это работает для меня внутри пользовательских Maven плагин (с использованием Maven 3.5.0):

ClassRealm classRealm = (ClassRealm) Thread.currentThread().getContextClassLoader(); 
MavenCli cli = new MavenCli(classRealm.getWorld()); 
cli.doMain(...); 

Сплетение Launcher sets the context class loader его ClassRealm, который имеет доступ к "глобальной" ClassWorld.

Не уверен, насколько стабильным является это решение, но пока оно выглядит хорошо.

Б импорт:

import org.codehaus.plexus.classworlds.ClassWorld; 
import org.codehaus.plexus.classworlds.realm.ClassRealm; 
import org.apache.maven.cli.MavenCli;