Maven2属性表示父目录

130

我有一个多模块项目,就像这个:

main-project/
    module1/
    module2/
        sub-module1/
        sub-module2/
        sub-module3/
        ...
    module3/
    module4/
    ...

我需要在Maven2中定义一组属性(这些属性取决于我想要发布项目的环境)。我不会使用<properties>,因为有很多属性...因此,我使用Properties Maven2插件
属性文件位于main-project/目录中。如何在主pom.xml文件中设置正确的目录,以便指定任何子模块在哪里找到属性文件?
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>properties-maven-plugin</artifactId>
    <version>1.0-alpha-1</version>
    <executions>
        <execution>
            <phase>initialize</phase>
            <goals>
                <goal>read-project-properties</goal>
            </goals>
            <configuration>
                <files>
                    <file>???/env_${env}.properties</file>
                </files>
            </configuration>
        </execution>
    </executions>
</plugin>

如果我只设置<file>env_${env}.properties</file>,那么当Maven2编译第一个模块时,它将找不到main-project/env_dev.properties文件。如果我设置<file>../env_${env}.properties</file>,则会在父级或任何子模块级别上引发错误...

2
只需使用${maven.multiModuleProjectDirectory} - qoomon
19个回答

199

尝试在每个pom中设置一个属性,以找到主项目目录。

在父pom中:

<properties>
    <main.basedir>${project.basedir}</main.basedir>
</properties>
在子元素中:
<properties>
    <main.basedir>${project.parent.basedir}</main.basedir>
</properties>

在孙子中:

<properties>
    <main.basedir>${project.parent.parent.basedir}</main.basedir>
</properties>

21
这些预设属性被移除了吗?${parent.basedir}在3.0.4中不再解析为任何内容。 - matt5784
9
是的,这行不通。${project.parent.basedir}会评估为null。 - Jared
24
我曾经成功地使用 ${project.basedir}/..,但这只适用于严格按目录层次结构组织的多模块项目。 - Jonathan
104
叹息。难以置信,Maven 让这变得如此困难。 - Stefan Haberl
6
我将尽力进行翻译,并保证原意不变。以下是需要翻译的内容:和Jonathan一样,我必须使用相对路径,但我觉得最好使用file.separator变量,像这样:<main.basedir>${project.basedir}${file.separator}..</main.basedir>。我必须像Jonathan一样使用相对路径,但我认为最好使用file.separator变量来编写,就像这样:<main.basedir>${project.basedir}${file.separator}..</main.basedir> - Enwired
显示剩余4条评论

49

至少在当前maven版本中(3.6.0),您可以使用${maven.multiModuleProjectDirectory}


3
尝试查找有关此内容的文档,似乎这是用于内部使用的,可能会在未来被删除/更改[MNG-6589](https://issues.apache.org/jira/browse/MNG-6589)。 - Greg Domjan
这是一个属性,您可以像其他属性一样使用。 - qoomon
2
我不确定我们是否应该使用这个答案。根据此工单,它是内部的,可能随时会消失。这也是为什么它没有在任何地方记录的原因。仍然没有干净的解决方案。 - Hilikus
它解析为我的Windows 10用户主目录。 - Dmitry Trifonov
1
它可能已经被删除了。但是2009年接受的答案中${project.parent.basedir}属性也被删除了,而那些不是内部的。所以...无论如何生活都是危险的 :P - MaximizedAction

32

使用 directory-maven-plugin 的 directory-of 目标

与其他建议不同的是:

  • 这个解决方案适用于多模块项目。
  • 它可以在构建整个项目或子模块时使用。
  • 无论您是从根文件夹还是子模块运行maven,都可以使用。
  • 不需要在每个子模块中设置相对路径属性!

该插件允许您将任何项目模块的绝对路径设置为您选择的属性。在我的项目中,我将其设置为根模块... 在我的项目根POM中:

<plugin>
    <groupId>org.commonjava.maven.plugins</groupId>
    <artifactId>directory-maven-plugin</artifactId>
    <version>0.1</version>
    <executions>
        <execution>
            <id>directories</id>
            <goals>
                <goal>directory-of</goal>
            </goals>
            <phase>initialize</phase>
            <configuration>
                <property>myproject.basedir</property>
                <project>
                    <groupId>com.my.domain</groupId>
                    <artifactId>my-root-artifact</artifactId>
                </project>
            </configuration>
        </execution>
    </executions>
</plugin>

从那时起,任何子模块pom中的${myproject.basedir}都始终具有项目根模块的路径。当然,您可以将该属性设置为任何模块,而不仅仅是根模块...


请不要在代码中出现"test"这个词,否则会引起各种问题。按照上面所示的方法操作可以完美解决。 - ElectronicBlacksmith
在这个帖子中提到的所有建议中,只有这个对我有效。 - undefined

15

我已经找到了解决我的问题的方法:使用Groovy Maven插件搜索属性文件。

由于我的属性文件必须在当前目录、../或../../中,所以我编写了一小段Groovy代码来检查这三个文件夹。

这是我的pom.xml的摘录:

<!-- Use Groovy to search the location of the properties file. -->
<plugin>
    <groupId>org.codehaus.groovy.maven</groupId>
    <artifactId>gmaven-plugin</artifactId>
    <version>1.0-rc-5</version>
    <executions>
        <execution>
            <phase>validate</phase>
            <goals>
                <goal>execute</goal>
            </goals>
            <configuration>
                <source>
                    import java.io.File;
                    String p = project.properties['env-properties-file'];
                    File f = new File(p); 
                    if (!f.exists()) {
                        f = new File("../" + p);
                        if (!f.exists()) {
                            f = new File("../../" + p);
                        }
                    }
                    project.properties['env-properties-file-by-groovy'] = f.getAbsolutePath();
            </source>
            </configuration>
        </execution>
    </executions>
</plugin>
<!-- Now, I can load the properties file using the new 'env-properties-file-by-groovy' property. -->
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>properties-maven-plugin</artifactId>
    <version>1.0-alpha-1</version>
    <executions>
        <execution>
            <phase>initialize</phase>
            <goals>
                <goal>read-project-properties</goal>
            </goals>
            <configuration>
                <files>
                    <file>${env-properties-file-by-groovy}</file>
                </files>
            </configuration>
        </execution>
    </executions>
</plugin>

这个方法可以工作,但我并不是很喜欢它。

如果你有更好的解决方案,请毫不犹豫地发表!


12

我认为问题在于你无法在maven中获取到父目录的绝对路径。

<抱怨>我听说这被称为反模式,但对于每个反模式,都存在真正的、合法的使用情况,而我厌倦了maven告诉我只能按照他们的模式操作。</抱怨>

因此,我找到的解决方法是使用antrun。请在子POM.xml中尝试以下操作:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.7</version>
    <executions>
        <execution>
            <id>getMainBaseDir</id>
            <phase>validate</phase>
            <goals>
                <goal>run</goal>
            </goals>
            <configuration>
                <exportAntProperties>true</exportAntProperties>
                <target>
                    <!--Adjust the location below to your directory structure -->
                    <property name="main.basedir" location="./.." />
                    <echo message="main.basedir=${main.basedir}"/>
                </target>
            </configuration>
        </execution>
    </executions>
</plugin>

如果你运行mvn verify,你应该看到类似这样的内容:

main:
     [echo] main.basedir=C:\src\parent.project.dir.name

然后你可以在其他插件中使用${main.basedir},以此类推。我花了一些时间才明白这一点,希望能对其他人有所帮助。


我该如何将它传递给Maven Surefire插件? - Kalpesh Soni

7

另一种替代方案:

在父POM文件中使用以下内容:

<properties>
   <rootDir>${session.executionRootDirectory}</rootDir>
<properties>

在子POM中,您可以引用这个变量。
主要注意事项:它强制您始终从主父POM目录执行命令。然后,如果您只想对某些特定模块运行命令(例如测试),请使用以下语法:
mvn test --projects
为了参数化“path_to_test_data”变量的surefire配置可能是:
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${surefire.plugin.version}</version>
    <configuration>
        <systemPropertyVariables>
            <path_to_test_data>${rootDir}/../testdata</path_to_test_data>
        </systemPropertyVariables>
    </configuration>
</plugin>

6
以下简洁的配置对我很有帮助。我需要这样的配置来运行CheckStyle,我将其放在项目根目录下的config目录中,以便我可以从主模块和子模块中运行它。
<profile>
    <id>root-dir</id>
    <activation>
        <file>
            <exists>${project.basedir}/../../config/checkstyle.xml</exists>
        </file>
    </activation>
    <properties>
        <project.config.path>${project.basedir}/../config</project.config.path>
    </properties>
</profile>

对于嵌套模块不起作用,但我确信可以使用几个具有不同exists的配置文件进行修改。 (我不知道为什么验证标记中应该有“../..”,而覆盖属性本身只有“..”,但它只能以这种方式工作。)


我不知道为什么这样做是有效的(额外的../),但这似乎是最干净的解决方案(我也遇到了checkstyle.xml配置的问题)。 - RockMeetHardplace

6
在我的情况下,它的工作方式如下:
...
<properties>
  <main_dir>${project.parent.relativePath}/..</main_dir>
</properties>
...

<plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>properties-maven-plugin</artifactId>
        <version>1.0-alpha-1</version>
        <executions>
          <execution>
            <phase>initialize</phase>
            <goals>
              <goal>read-project-properties</goal>
            </goals>
            <configuration>
              <files>
                 <file>${main_dir}/maven_custom.properties</file>
              </files>
            </configuration>
          </execution>
        </executions>
</plugin>

4
我找到了一个解决方法来解决这个问题:使用${parent.relativePath}。
<parent>
    <artifactId>xxx</artifactId>
    <groupId>xxx</groupId>
    <version>1.0-SNAPSHOT</version>
    <relativePath>..</relativePath>
</parent>
<build>
    <filters>
        <filter>${parent.relativePath}/src/main/filters/filter-${env}.properties</filter>
    </filters>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>

2
这可能并不总是安全的;${parent.relativePath} 可能包含文件名,例如 "../pom.xml"。 - pimlottc

3
您正在C项目中工作,C项目是B项目的子模块,而B项目是A项目的子模块。您尝试从C项目访问D模块的src/test/config/etc目录。D也是A项目的子模块。以下表达式使得获取URI路径成为可能:
-Dparameter=file:/${basedir}/../../D/src/test/config/etc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接