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

2022-09-02 10:01:13

如何获取 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 文件相同的信息。

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

干杯!


答案 1

我做到了:-)

help:effective-pom and dependency:tree 真的根本无济于事。

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

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

操作方法如下:

1) 获取模型解析器

您将需要一个 interface org.apache.maven.model.resolution.ModelResolver 的实例。不幸的是,maven不能通过依赖注入轻松提供一个(至少我找不到一个),所以我们必须构建一个。为了使事情变得更好,该接口的仅有两个实现是受包保护的,因此您需要使用一些反射魔术来实例化它。实现它的具体类是DefaultModelResolverProjectModelResolver。我能够像这样构建一个默认模型解析器

/**
 * 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) 构建模型

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


推荐