简体   繁体   English

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

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

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. 我正在构建一个对一组模块执行一些验证规则的Maven插件。 Those modules' pom files are available but they're not part of the reactor when the plugin is executed. 这些模块的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. 它可以工作,但是Model对象仅具有与pom文件相同的信息。

How can I improve that method so that I can obtain a "fully resolved" Model object? 如何改进该方法,以便可以获得“完全解析”的Model对象? By fully resolved, I mean: with all the transitive dependencies and everything else from the parent poms. 通过完全解决,我的意思是:具有所有传递依赖项以及父poms的所有其他项。

Cheers! 干杯!

I did it :-) 我做的 :-)

help:effective-pom and dependency:tree really did not help at all. help:有效的pom和依赖关系:tree根本没有帮助。

I had to look at how maven builds the Model for the MavenProject that gets injected in the mojo. 我必须看一下maven如何为注入到mojo中的MavenProject构建模型。 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. help:effective-pom已经收到了解析的模型,并且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 . 您将需要接口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. 不幸的是,maven无法通过依赖注入轻松地提供一个(至少我找不到一个),因此我们必须构建一个。 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 DefaultModelResolver and ProjectModelResolver . 实现它的具体类是DefaultModelResolverProjectModelResolver I was able to build a DefaultModelResolver like this 我能够建立像这样的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: 当您拥有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;
}

Doesn't look pretty, but it worked for me.. :P 看起来不漂亮,但是对我有用。.:P

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中

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 (eg bundle...) In the target pom project make sure the plugins associated to those packaging are installed in your current project. 如果您有一些特殊的包装(例如捆绑包...),请在目标pom项目中确保与这些包装关联的插件已安装在当前项目中。

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 Project from the read pom. 快速浏览之后,您似乎需要根据读取的pom构建一个Maven Project 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. 这可能涉及许多步骤,包括解析POM的父项目,下载和解析其他Maven插件工件以及将所有引用连接在一起。

Reading the child-level pom alone won't do it. 仅阅读儿童级别的pom不会做到这一点。

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=markup for 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 mvndependency: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? 也许您可以同时创建两者?

Just in case anyone want it, here is an example running in Groovy. 万一有人想要它,下面是在Groovy中运行的示例。 It uses the Grape to dynamically load the depdencies needed to consume the pom.xml. 它使用Grape来动态加载消耗pom.xml所需的依赖关系。 It loads both the runtime classpath and the test classpath. 它同时加载运行时类路径和测试类路径。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM