2012-07-17 74 views
12

如何獲得完整解析的pom文件模型?如何獲得完整解析的pom文件模型?

這基本上是How can i programmaticaly build the effective model of a pom file?

我建立執行對一組模塊的一些驗證規則Maven插件的改述。 這些模塊的pom文件可用,但在插件執行時它們不是反應堆的一部分。

我可以讀取POM文件並獲得使用該方法(爲簡單起見除去異常處理)相應的模型對象:

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; 
} 

而且它的工作原理,但模型對象僅具有相同的信息,所述POM文件具有。

我該如何改進該方法,以便可以獲得「完全解析的」模型對象? 完全解決,我的意思是:與所有的傳遞依賴和其他所有從父poms。

乾杯!

+0

您可以詳細介紹一下驗證規則嗎? – khmarbaise 2012-07-18 13:01:21

回答

9

我做到了:-)

幫助:有效,聚甲醛和依賴:樹確實幫助的。

我不得不看看Maven如何爲MavenProject注入mojo的模型。 help:effective-pom已經接收到已解析的模型,並且依賴關係:樹只構建一個DependencyGraph,但它不會將整個模型加載到內存中。

通過使用下面的代碼,我能夠獲得一個Model對象,其中包含來自父級的所有信息,已解析的$ {property}表達式以及擴展的傳遞依賴性。

方法如下:

1)獲取ModelResolver

您需要接口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)建立模型

當你有一個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

+0

它也適用於我。但我真的希望有一個更清晰的方法。 – 2013-08-30 20:26:27

+0

你知道嗎,maven-dependency-plugin是否和你的代碼做類似的事情? – 2015-02-13 22:43:49

+0

ProjectModelResolver不是包私有的,但它需要一個包私有類ReactorModelPool – Puce 2016-12-10 12:50:21

1

你尋求的源代碼是在help:effective-pom,某處。

---編輯更新---

a quick glance後,它似乎是你需要從讀POM生成Maven Project。這可能涉及許多步驟,包括解析POM的父項目,下載並解析其他Maven插件工件,並將所有參考連接在一起。

單獨閱讀孩子級別的pom不會這樣做。

+0

謝謝!我會看一看。順便說一句,你應該檢查你的[apache服務器](http://edwinbuck.com/);-) – 2012-07-17 15:58:48

+0

@TonyLâmpada祝你好運,而且Apache服務器確實有用,如果你知道正確的URL。 :)它只是不是一個虛榮的網站,如果這是你所期待的。 – 2012-07-17 16:09:56

+0

help:effective-pom不會幫助我,反之亦然 - 它使用從project.getModel()獲取的已建模型。但是那個模型已經在別的地方預先建好了。 – 2012-10-03 19:07:35

1

當「mvn help:effective-pom」執行時,maven help插件會做類似的事情。

查看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依賴性:樹目標,這是否: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

也許你可以創建兩者的混合?

+0

謝謝,我也來看看吧! – 2012-07-17 15:59:59

+0

既然effective-pom爲當前的maven Project做了這些工作,通常它並沒有像你想象的那麼有幫助。 effective-pom假定通常存在的maven框架已經完成了一些工作。所要求的更多的是第二個maven項目,並且足以將其引入完全解決的pom。 – 2015-01-23 16:24:26

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

就是這樣。它應該工作。如果你有一些特殊的包裝(例如bundle ...)在目標pom項目中,確保與當前項目中安裝的包裝相關的插件。

+0

謝謝,你救了我的一天! :-) – eerriicc 2015-08-13 15:07:37

+0

@ romain-gilles你使用哪個版本的依賴關係?看起來MavenProjectBuilder在3.x中已被棄用,但RepositorySystem在2.2.1中不可用。在3.x ProjectBuilder是可用的,但它不能建立MavenProject – 2016-09-20 15:01:51

+0

我找到了我的問題的答案,下面的詳細信息http://stackoverflow.com/a/39609354/157591 – 2016-09-21 08:33:40

0

爲了防止任何人需要,下面是一個在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"); 
6

羅曼提供了良好的答案above,但它使用從行家刪除已過時的類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

+0

如何注入'RepositorySystem' ProjectBuilder'和'MavenSession'成我自己的'Component' – DarVar 2017-05-24 10:08:22

+0

@Component(role = MyResolver.class,instantiationStrategy =「per-lookup」) public class MyResolver {....} – DarVar 2017-05-24 10:09:10