Подтвердить что ты не робот

Как получить полностью разрешенную модель файла pom?

Как получить полностью разрешенную модель файла pom?

Это в основном перефразирование Как я могу программно построить эффективную модель файла pom?

Я создаю плагин maven, который выполняет некоторые правила проверки относительно набора модулей. Файлы pom этих модулей доступны, но они не являются частью реактора при выполнении плагина.

Я могу прочитать файл pom и получить соответствующий объект Model с помощью этого метода (удаленная обработка исключений для простоты):

private Model pomToModel(String pathToPom) throws Exception {
    BufferedReader in = new BufferedReader(new FileReader(pathToPom));
    MavenXpp3Reader reader = new MavenXpp3Reader();
    Model model = reader.read(in);
    return model;
}

И он работает, но объект Model имеет только ту же информацию, что и файл pom.

Как я могу улучшить этот метод, чтобы получить "полностью разрешенный" объект модели? Полностью разрешенный, я имею в виду: со всеми транзитивными зависимостями и всем остальным от родительских попов.

Ура!

4b9b3361

Ответ 1

Я сделал это: -)

help: effective-pom и dependency: дерево действительно помогло не.

Мне пришлось посмотреть, как maven создает модель для MavenProject, которая вводится в mojo. help: effective-pom уже получает разрешенную модель и зависимость: дерево только создает DependencyGraph, но не загружает всю модель для памяти в память.

Используя приведенный ниже код, я смог получить объект Model со всей информацией от родителя, с разрешенными выражениями ${property} и расширенными транзитивными зависимостями.

Вот как:

1) Получите ModelResolver

Вам понадобится экземпляр интерфейса org.apache.maven.model.resolution.ModelResolver. К сожалению, maven не обеспечивает одно легко через инъекцию зависимости (по крайней мере, я не мог найти ее), поэтому нам придется ее построить. Чтобы сделать вещи еще лучше, только две реализации этого интерфейса защищены пакетом, поэтому вам нужно использовать некоторую магию отражения для ее создания. Конкретными классами, которые его реализуют, являются DefaultModelResolver и ProjectModelResolver. Мне удалось создать DefaultModelResolver, как этот

/**
 * The Maven Project Object
 * 
 * @parameter expression="${project}"
 * @required2.0
 * @readonly
 */
protected MavenProject project;

/**
 * @component
 */
protected ArtifactResolver artifactResolver;

/**
 * @component
 */
protected RemoteRepositoryManager remoteRepositoryManager;

private Object invoke( Object object, String method )
        throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
    return object.getClass().getMethod( method ).invoke( object );
}

private org.apache.maven.model.resolution.ModelResolver makeModelResolver() throws MojoExecutionException {
    try {
        ProjectBuildingRequest projectBuildingRequest =
        (ProjectBuildingRequest) invoke( project, "getProjectBuildingRequest" );

        Class c = Class.forName("org.apache.maven.repository.internal.DefaultModelResolver");
        Constructor ct = c.getConstructor(new Class[]{RepositorySystemSession.class, 
                RequestTrace.class, String.class,
                ArtifactResolver.class, RemoteRepositoryManager.class,
                List.class});
        ct.setAccessible(true);
        return (org.apache.maven.model.resolution.ModelResolver) ct.newInstance(new Object[]{
                projectBuildingRequest.getRepositorySession(), 
                null, null, artifactResolver, remoteRepositoryManager, 
                project.getRemoteProjectRepositories()});
    } catch (Exception e) {
        throw new MojoExecutionException("Error instantiating DefaultModelResolver", e);
    }
}

2) Постройте модель

Когда у вас есть modelResolver, вы можете построить модель из файла pom следующим образом:

public Model resolveEffectiveModel(File pomfile) {
    try {
        return modelBuilder.build(makeModelBuildRequest(pomfile)).getEffectiveModel();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }   
}

private ModelBuildingRequest makeModelBuildRequest(File artifactFile) {
    DefaultModelBuildingRequest mbr = new DefaultModelBuildingRequest();
    mbr.setPomFile(artifactFile);
    mbr.setModelResolver(modelResolver); // <-- the hard-to-get modelResolver
    return mbr;
}

Не выглядит красиво, но это сработало для меня..: P

Ответ 2

Romain предоставил хороший ответ выше, но он использовал устаревший класс, который был удален из maven 3.x. Обновленная версия:

@Parameter( defaultValue = "${project}", readonly = true )
private MavenProject project;

@Component
private RepositorySystem repositorySystem;

@Component
private ProjectBuilder mavenProjectBuilder;

@Parameter( defaultValue = "${session}", readonly = true )
private MavenSession session;

private MavenProject getMavenProject(String groupId, String artifactId, String version) throws ProjectBuildingException {

    Artifact pomArtifact = repositorySystem.createProjectArtifact(groupId, artifactId, version);
    ProjectBuildingResult build = mavenProjectBuilder.build(pomArtifact, session.getProjectBuildingRequest());

    return build.getProject();

}

Рабочий пример представлен в hierarchy-maven-plugin

Ответ 3

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

@Component
private RepositorySystem repositorySystem;

@Component
private MavenProjectBuilder mavenProjectBuilder;

@Parameter(property = "project.remoteArtifactRepositories")
protected List<ArtifactRepository> remoteRepositories;

@Parameter(property = "localRepository")
protected ArtifactRepository localRepository;

...
Artifact pomArtifact = repositorySystem.createProjectArtifact(groupId, artifactId,version);
MavenProject project = mavenProjectBuilder.buildFromRepository(pomArtifact
                          , remoteRepositories, localRepository);

И что это. Он должен работать. Если у вас есть специальная упаковка (например, пакет...) В проекте target pom убедитесь, что плагины, связанные с этой упаковкой, установлены в вашем текущем проекте.

Ответ 4

Исходный код, который вы ищете, находится в help:effective-pom, где-то.

--- Изменить обновление ---

После быстрый взгляд, казалось бы, вам нужно будет построить Maven Project из прочитанного pom. Это, вероятно, будет включать в себя ряд шагов, которые включают разрешение родительского проекта POM, загрузку и разбор других артефактов Maven и подключение всех ссылок вместе.

Чтение только одного уровня на уровне ребенка не будет.

Ответ 5

Плагин поддержки maven делает что-то подобное, когда выполняется "mvn help: effective-pom".

см. http://svn.apache.org/viewvc/maven/plugins/tags/maven-help-plugin-2.1.1/src/main/java/org/apache/maven/plugins/help/EffectivePomMojo.java?view=markup для источников.

Я думаю, что это не покажет переходные зависимости.

Зависимость mvn: tree делает это: http://svn.apache.org/viewvc/maven/plugins/tags/maven-dependency-plugin-2.4/src/main/java/org/apache/maven/plugin/dependency/TreeMojo.java?view=markup

Может быть, вы можете создать смесь обоих?

Ответ 6

На всякий случай, если кто-то захочет этого, вот пример, выполняющийся в Groovy. Он использует Grape для динамической загрузки depdencies, необходимых для использования pom.xml. Он загружает как путь к среде выполнения, так и путь к тестовому классу.

@Grapes([
         @Grab(group='org.apache.maven', module='maven-core', version='3.0.5'),
         @Grab(group='org.apache.maven', module='maven-compat', version='3.0.5'),
         @Grab(group='com.jcabi', module='jcabi-aether', version='0.10.1')
         ])

         // http://www.programcreek.com/java-api-examples/index.php?api=org.apache.maven.project.MavenProjectBuilder See # 20


import org.codehaus.plexus.DefaultPlexusContainer
import org.apache.maven.project.MavenProjectBuilder
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.project.DefaultProjectBuilderConfiguration
import org.apache.maven.artifact.repository.DefaultArtifactRepository
import com.jcabi.aether.Aether
import org.sonatype.aether.repository.RemoteRepository;
import org.sonatype.aether.util.artifact.DefaultArtifact;
import org.sonatype.aether.artifact.Artifact;


container=new DefaultPlexusContainer();
projectBuilder=(MavenProjectBuilder)container.lookup(MavenProjectBuilder.class.getName());
layout=(ArtifactRepositoryLayout)container.lookup(ArtifactRepositoryLayout.class.getName(),"default");

def projectInfo(localRepoUrl, pom){

    File pomFile = new File(pom);
    String localRepoUrl2 = "file://" + localRepoUrl;
    File local = new File(localRepoUrl);



    ArtifactRepository localRepo=new DefaultArtifactRepository("local",localRepoUrl2,layout);
    pbConfig=new DefaultProjectBuilderConfiguration().setLocalRepository(localRepo);
    project = projectBuilder.build( pomFile, pbConfig );
    aether = new Aether(project, local);
    [ runtime: resolveDependencies(aether, project, "runtime"),
      test : resolveDependencies(aether, project, "test") ];
}


def resolveDependencies (aether, project, scope) {
    depLists = project.getDependencies().collect { 

        art = new DefaultArtifact(it.getGroupId(), it.getArtifactId(), it.getClassifier(), it.getType(), 
                                  it.getVersion());
        Collection<Artifact> deps = aether.resolve( art, scope );

        deps.collect{  it.getFile().getAbsolutePath() }

    }

    [ dependencies : depLists.collect {it.first()},  classpath : depLists.flatten() ]
}



println projectInfo("c:/Users/lpmsmith/.m2/repository", "pom.xml");