java 如何获得完全解析的 pom 文件模型?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11525318/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 05:26:01  来源:igfitidea点击:

How do I obtain a fully resolved Model of a pom file?

javamavenmaven-3pom.xml

提问by Tony Lampada

How do I obtain a fully resolved Model of a pom file?

如何获得完全解析的 pom 文件模型?

This is basically a rephrasing of How can i programmaticaly build the effective model of a pom file?

这基本上是对如何以编程方式构建 pom 文件的有效模型的重新表述?

I'm building a maven plugin that performs some validation rules against a set of modules. Those modules' pom files are available but they're not part of the reactor when the plugin is executed.

我正在构建一个 maven 插件,它对一组模块执行一些验证规则。这些模块的 pom 文件可用,但在执行插件时它们不是反应器的一部分。

I can read a pom file and obtain the corresponding Model object using this method (removed exception handling for simplicity):

我可以使用此方法读取 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;
}

And it works but the Model object has only the same information that the pom file has.

它可以工作,但模型对象仅具有与 pom 文件相同的信息。

How can I improve that method so that I can obtain a "fully resolved" Model object? By fully resolved, I mean: with all the transitive dependencies and everything else from the parent poms.

如何改进该方法,以便获得“完全解析”的 Model 对象?通过完全解析,我的意思是:具有所有传递依赖项以及来自父 poms 的所有其他内容。

Cheers!

干杯!

采纳答案by Tony Lampada

I did it :-)

我做的 :-)

help:effective-pom and dependency:tree really did nothelp at all.

帮助:有效,聚甲醛和依赖:树真的没有帮助的。

I had to look at how maven builds the Model for the MavenProject that gets injected in the mojo. help:effective-pom already receives the resolved Model, and dependency:tree only builds a DependencyGraph, but it doesn't load the whole model for a pom into memory.

我不得不看看 maven 如何为注入 mojo 的 MavenProject 构建模型。help:effective-pom 已经接收到解析后的Model,并且dependency:tree 只构建了一个DependencyGraph,但它不会将一个pom 的整个模型加载到内存中。

By using the code below I was able to get a Model object with all the information from the parent, with resolved ${property} expressions, and expanded transitive dependencies.

通过使用下面的代码,我能够从父级获取包含所有信息的 Model 对象,解析 ${property} 表达式和扩展的传递依赖项。

Here's how:

就是这样:

1) Get a ModelResolver

1) 获取一个 ModelResolver

You will need an instance of interface org.apache.maven.model.resolution.ModelResolver. Unfortunately, maven doesn't provide one easily via dependency injection (at least I couldn't find one), so we'll have to build one. To make things even better, the only two implementations of that interface are package protected, so you need to use some reflection magic to instantiate it. The concrete classes that implement it are DefaultModelResolverand ProjectModelResolver. I was able to build a DefaultModelResolver like this

您将需要一个接口 org.apache.maven.model.resolution.ModelResolver的实例。不幸的是,maven 不能通过依赖注入轻松提供一个(至少我找不到),所以我们必须构建一个。为了让事情变得更好,该接口仅有的两个实现是包保护的,因此您需要使用一些反射魔法来实例化它。实现它的具体类是DefaultModelResolverProjectModelResolver。我能够像这样构建一个 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) Build the Model

2) 建立模型

When you have a modelResolver, you can build the Model from a pom file like this:

当你有一个模型解析器时,你可以从一个 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;
}

Doesn't look pretty, but it worked for me.. :P

看起来不漂亮,但它对我有用.. :P

回答by Peter Szanto

Romain provided the good answer above, but it was using a deprecated class that was removed from maven 3.x The updated version is this :

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();

}

A working example is in the hierarchy-maven-plugin

一个工作示例在hierarchy-maven-plugin中

回答by Romain

Maybe is too late for you but if it can help others in the future. So I did it like that:

也许对你来说太晚了,但如果它可以在未来帮助别人。所以我是这样做的:

@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);

And that's it. It should work. If you have some special packaging (e.g. bundle...) In the target pom project make sure the plugins associated to those packaging are installed in your current project.

就是这样。它应该工作。如果您在目标 pom 项目中有一些特殊的包装(例如捆绑包...),请确保与这些包装相关的插件已安装在您当前的项目中。

回答by M Smith

Just in case anyone want it, here is an example running in Groovy. It uses the Grape to dynamically load the depdencies needed to consume the pom.xml. It loads both the runtime classpath and the test classpath.

以防万一有人需要它,这里有一个在 Groovy 中运行的示例。它使用 Grape 动态加载使用 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");

回答by Edwin Buck

The source code you seek is in help:effective-pom, somewhere.

您寻找的源代码在help:effective-pom某处。

--- Edit update ---

--- 编辑更新 ---

After a quick glance, it would seem that you would need to build a Maven Projectfrom the read pom. This likely will involve a number of steps that include resolution of the parent project of the POM, downloading and parsing other Maven plugin artifacts and wiring all of the references together.

快速浏览之后,您似乎需要Project从 read pom构建一个 Maven 。这可能涉及许多步骤,包括解析 POM 的父项目、下载和解析其他 Maven 插件工件以及将所有引用连接在一起。

Reading the child-level pom alone won't do it.

单独阅读儿童级别的 pom 是行不通的。

回答by wemu

the maven help plugin does something similar when "mvn help:effective-pom" is executed.

当执行“mvn help:effective-pom”时,maven 帮助插件会做类似的事情。

see 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=markupfor the sources.

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 =来源的标记

I think this will not show the transitive depedencies.

我认为这不会显示传递依赖。

The mvn dependency:tree goal does that: 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

mvn dependency: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

maybe you can create a mixture of both?

也许你可以创造两者的混合物?