Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

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

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.

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

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.

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.

Cheers!

like image 298
Tony Lâmpada Avatar asked Jul 17 '12 14:07

Tony Lâmpada


People also ask

How do you resolve problems in POM xml?

You can usually resolve these errors by updating Maven dependencies as follows: Right-click on your top-level project (not on the pom. xml file) in the Project Explorer view. From the menu, choose Maven > Update project.

How do you show an effective POM?

You can execute this goal using the following command: # mvn help:effective-pom.

What is a pom FIE in a Maven project?

What is a POM? A Project Object Model or POM is the fundamental unit of work in Maven. It is an XML file that contains information about the project and configuration details used by Maven to build the project. It contains default values for most projects.


2 Answers

I did it :-)

help:effective-pom and dependency:tree really did not help 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.

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.

Here's how:

1) Get a 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 DefaultModelResolver and ProjectModelResolver. I was able to build a DefaultModelResolver like this

/**
 * 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

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

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

like image 187
Tony Lâmpada Avatar answered Sep 21 '22 13:09

Tony Lâmpada


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 :

@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

like image 42
Peter Szanto Avatar answered Sep 23 '22 13:09

Peter Szanto