257

I have two projects: Parent project: A, Sub project: B

A/pom.xml:

<groupId>com.dummy.bla</groupId>
<artifactId>parent</artifactId>
<version>0.1-SNAPSHOT</version>
<packaging>pom</packaging>

And in B/pom.xml, I have:

    <parent>
        <groupId>com.dummy.bla</groupId>
        <artifactId>parent</artifactId>
        <version>0.1-SNAPSHOT</version>     
    </parent>

    <groupId>com.dummy.bla.sub</groupId>
    <artifactId>kid</artifactId>

I want B to inherit the version from parent, so the only place in my case I need to put 0.1-SNAPSHOT is A/pom.xml. But if i remove the <version>0.1-SNAPSHOT</version> from B/pom.xml under the parent section, maven complains about the missing version for the parent.

Is there a way I can just use ${project.version} or something like this to avoid having 01.-SNAPSHOT in both poms?

Zoe
  • 27,060
  • 21
  • 118
  • 148
Shengjie
  • 12,336
  • 29
  • 98
  • 139
  • 5
    You will have to wait for Maven 3.1 for that, I'm afraid. – Perception May 14 '12 at 11:18
  • 3
    http://jira.codehaus.org/browse/MNG-624 – Tim May 23 '13 at 09:52
  • possible duplicate of [Can you inherit the version from the parent POM in Maven?](http://stackoverflow.com/questions/8026783/can-you-inherit-the-version-from-the-parent-pom-in-maven) – blong Jan 22 '14 at 17:42
  • 1
    The link above has moved. The final status was "Closed / Won't Fix" https://issues.apache.org/jira/browse/MNG-624 – jocull Jul 11 '18 at 14:24

11 Answers11

159

Since Maven 3.5.0 you can use the ${revision} placeholder for that. The use is documented here: Maven CI Friendly Versions.

In short the parent pom looks like this (quoted from the Apache documentation):

<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.apache</groupId>
    <artifactId>apache</artifactId>
    <version>18</version>
  </parent>
  <groupId>org.apache.maven.ci</groupId>
  <artifactId>ci-parent</artifactId>
  <name>First CI Friendly</name>
  <version>${revision}</version>
  ...
  <properties>
    <revision>1.0.0-SNAPSHOT</revision>
  </properties>
  <modules>
    <module>child1</module>
    ..
  </modules>
</project>

and the child pom like this

<project>
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>org.apache.maven.ci</groupId>
    <artifactId>ci-parent</artifactId>
    <version>${revision}</version>
  </parent>
  <groupId>org.apache.maven.ci</groupId>
  <artifactId>ci-child</artifactId>
   ...
</project>

You also have to use the Flatten Maven Plugin to generate pom documents with the dedicated version number included for deployment. The HowTo is documented in the linked documentation.

Also @khmarbaise wrote a nice blob post about this feature: Maven: POM Files Without a Version in It?

FrVaBe
  • 47,963
  • 16
  • 124
  • 157
  • 1
    I configured my project like you described, but without the "Flatten Maven Plugin" and it seems to work as expected, is this possible? Also I got an error with maven 3.2.1, but maven 3.3.9+ seems to work fine. – maxeh Oct 01 '19 at 14:48
  • 2
    @Max It depends what you define as "work as expected". I guess the build will pass but install/deploy to a repository will probably be no good idea because there is no version number in the child pom but only a placeholder (see [documentation](https://maven.apache.org/maven-ci-friendly.html#Install_.2F_Deploy)) – FrVaBe Oct 02 '19 at 11:42
  • I use ${revision} in parent pom with default property (0.1-default. Child poms also use ${revision}. I use "mvn clean install -Drevision=0.1.${bamboo.buildNumber}". When I scan the logs of the deployment everything is set to 0.1.820 and 0.1-default is not even in the logs (820 is the buildNumber). When I scan the resulting jar I see "Implementation-Version: 0.1.820" in the manifest, and also "version=0.1.820" in a pom.properties file. The pom file itself has ${revision}. So I think it's fine? – maxeh Oct 02 '19 at 12:40
  • 1
    @Max Try to resolve a jar where the version is `${revision}` in the pom (in the maven repository) as dependency in another project. I do not think that this will work. – FrVaBe Oct 03 '19 at 08:56
  • This is useful except when I do a release. That replaces `${revision}` in the version tag with the new version – Mike D Dec 06 '19 at 18:20
  • 1
    @MikeD Not having a placeholder in released versions is most likely that what you want to have. Otherwise a Repository Manager (or even Maven itself) would never be able to identify a released version. – FrVaBe Dec 09 '19 at 07:42
  • @FrVaBe I wasn't specific enough. To clarify, the next dev version (`-SNAPSHOT`) replaces the `${revision}` in the version tag. – Mike D Dec 09 '19 at 20:39
  • @MikeD Oh, I guess you are using the release plugin. In this case thinks might not work as expected - but that would rather be an issue on the release plugin. – FrVaBe Dec 10 '19 at 09:09
  • This works great until you have to specify your parent version as a range. (in your example apache version `[18, 19)` or similar) Then this unresolved bug comes into play :( https://issues.apache.org/jira/browse/MNG-6727 – Ralf Oct 19 '20 at 13:24
  • 2
    @Ralf I stopped thinking version ranges was a good idea years ago. You can't get a reproducible build with it. So I do not use them anymore. – FrVaBe Oct 23 '20 at 14:52
  • @FrVaBe that could be true - but used like that in a current project I'm in. And it's a maven feature just like the CI Friendly Versions. There is no obvious reason why those 2 features should not work together in harmony. – Ralf Oct 27 '20 at 12:40
  • Heads-up: the `${revision}` placeholder used with the **flatten-maven-plugin** doesn't seem to work with `mvn install --resume-from :module-name`, but otherwise is working for me. – pbatey Jun 29 '22 at 23:26
107

EDIT: Since Maven 3.5.0 there is a nice solution for this using ${revision} placeholder. See FrVaBe's answer for details. For previous Maven versions see my original answer below.


No, there isn't. You always have to specify parent's version. Fortunately, it is inherited as the module's version what is desirable in most cases. Moreover, this parent's version declaration is bumped automatically by Maven Release Plugin, so - in fact - it's not a problem that you have version in 2 places as long as you use Maven Release Plugin for releasing or just bumping versions.

Notice that there are some cases when this behaviour is actually pretty OK and gives more flexibility you may need. Sometimes you want to use some of previous parent's version to inherit, however that's not a mainstream case.

Michał Kalinowski
  • 16,925
  • 5
  • 35
  • 48
  • 7
    Nowadys you can use the `${revision}` placeholder for this. See my answer ;-) – FrVaBe Aug 22 '18 at 14:30
  • 3
    This is now out of date - check @FrVaBe's answer here: https://stackoverflow.com/a/51969067/514483 – robd Aug 22 '18 at 17:05
  • @FrVaBe what if we have nested parents with different versions? We can not use one ${revision} property there, it is not enough. – halil Oct 10 '19 at 06:19
  • @halil The question is about inheriting a version from a parent with the goal to have the same version in two artifacts. If you have different parents with different versions (in an inheritance hierarchy) you probably will not make them all the same version. I therefore do not fully understand the comment. – FrVaBe Oct 10 '19 at 07:16
  • this does not seem to work with Maven 3.6.3 - use mvn versions:set in this answer https://stackoverflow.com/a/31206432/57033 – hello_earth Apr 25 '21 at 19:20
  • @hello_earth, this is also not working. we are currently using maven-3.6.3. we are facing this issue. – Ramesh Thiyagarajan Jun 23 '23 at 10:16
92

Maven is not designed to work that way, but a workaround exists to achieve this goal (maybe with side effects, you will have to give a try). The trick is to tell the child project to find its parent via its relative path rather than its pure maven coordinates, and in addition to externalize the version number in a property :

Parent pom

<groupId>com.dummy.bla</groupId>
<artifactId>parent</artifactId>
<version>${global.version}</version>
<packaging>pom</packaging>

<properties>
   <!-- Unique entry point for version number management --> 
   <global.version>0.1-SNAPSHOT</global.version>
</properties>

Child pom

<parent>
   <groupId>com.dummy.bla</groupId>
   <artifactId>parent</artifactId>
   <version>${global.version}</version>
   <relativePath>..</relativePath>    
</parent>

<groupId>com.dummy.bla.sub</groupId>
<artifactId>kid</artifactId>

I used that trick for a while for one of my project, with no specific problem, except the fact that maven logs a lot of warnings at the beginning of the build, which is not very elegant.

EDIT

Seems maven 3.0.4 does not allow such a configuration anymore.

Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
Yanflea
  • 3,876
  • 1
  • 14
  • 14
  • 2
    yeah, I am afraid maven is not designed to work that way, better just stick with putting the versions in the sub pom.xml. maven release plugin doesn't really care about the versions there anyway. – Shengjie May 14 '12 at 12:07
  • Totally agree. If you really want to use the release plugin, the other answer is definitely the best, stick with the version number in both pom.xml. This is the standard way to implement inheritance with maven. I just thought interesting to mention that such a workaround exist, just in case. – Yanflea May 14 '12 at 12:17
  • There is a problem with this solution: it doesn't work, at least with Maven 3.0.4. – Michał Kalinowski May 14 '12 at 12:19
  • I haven't tried maven 3.0.4 yet. It works with maven 3.0.3 (but with a lot a complaints from the compiler as I said). I edit my post to precise that info (thks). – Yanflea May 14 '12 at 12:25
  • 7
    for 3.0.5 works ok. you should put on the very top though. – ses Aug 08 '13 at 20:33
  • 9
    It works in 3.2.3. The location of does not matter. You'll get a warning though: `'version' contains an expression but should be a constant.` – kapex Nov 02 '14 at 10:39
  • 10
    Please, be careful with this. This doens't work when your project is being referenced by another project. The property won't be resolved and will be treated literally (i.e. ${my.version}). This will lead to failure when resolving dependencies. – spekdrum Feb 10 '16 at 13:55
  • In fact in newer Maven versions this is reported with a warning. – spekdrum Feb 10 '16 at 14:33
  • 2
    I've been also using this for quite a while now and it works just fine (currently with maven 3.3.9) for a single multi module project. However as soon as your project becomes a dependency of another project things get reaaaaally tricky. I really suggest adopting the suggestion proposed by @pay below. – ingenious May 17 '16 at 06:11
  • 1
    If you use `mvn release:prepare release:perform` the variable `global.variable` will be resolved and neither be used in the release nor in the new snapshot! – Grim Jul 23 '16 at 21:16
92

The easiest way to update versions IMO:

$ mvn versions:set -DgenerateBackupPoms=false

(do that in your root/parent pom folder).

Your POMs are parsed and you're asked which version to set.

Stefan van den Akker
  • 6,661
  • 7
  • 48
  • 63
pai
  • 977
  • 7
  • 6
  • 23
    You can also add -DnewVersion={versionToBeUpdated} to avoid entering it interactively. – Mukesh Jun 20 '16 at 22:36
  • 1
    I think this is the best answer, it automates version changes without breaking subprojects (which you wouldn't be able to reference without the parent pom). – Tarek Feb 27 '18 at 13:26
  • Yup! This is the answer. – aaiezza Feb 23 '19 at 14:20
  • If child and parent pom version are initially different, first update them to match, `mvn versions:update-child-modules` else all child module pom version will be skipped. – Gautam Tadigoppula Mar 10 '20 at 20:43
24

As Yanflea mentioned, there is a way to go around this.

In Maven 3.5.0 you can use the following way of transferring the version down from the parent project:

Parent POM.xml

<project ...>
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mydomain</groupId>
    <artifactId>myprojectparent</artifactId>
    <packaging>pom</packaging>
    <version>${myversion}</version>
    <name>MyProjectParent</name>

    <properties>
        <myversion>0.1-SNAPSHOT</myversion>
    </properties>

    <modules>
        <module>modulefolder</module>
    </modules>
    ...
</project>

Module POM.xml

<project ...>
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.mydomain</groupId>
        <artifactId>myprojectmodule</artifactId>
        <version>${myversion}</version> <!-- This still needs to be set, but you can use properties from parent -->
    </parent>

    <groupId>se.car_o_liner</groupId>
    <artifactId>vinno</artifactId>
    <packaging>war</packaging>
    <name>Vinno</name>
    <!-- Note that there's no version specified; it's inherited from parent -->
    ...
</project>

You are free to change myversion to whatever you want that isn't a reserved property.

Zoe
  • 27,060
  • 21
  • 118
  • 148
eFox
  • 685
  • 8
  • 17
  • 4
    When referencing a module from another project, Maven doesn't resolve the property. Is that normal? – Leo Lozes Feb 26 '18 at 12:32
  • I believe that question may be worthy of its own entry and not be in a comment like this. Without seeing your code I can only wildly guess. – eFox Feb 26 '18 at 18:10
  • @LeoLozes Did you solved your problem(refrence module from another project)? – Morteza Malvandi Jan 30 '19 at 07:14
  • @MortezaMalvandi yes! My answer is at the bottom :) – Leo Lozes Jan 30 '19 at 11:10
  • 5
    Maven 3.6.0 gives warning for this configuration: "It is highly recommended to fix these problems because they threaten the stability of your build." "For this reason, future Maven versions might no longer support building such malformed projects." – d2k2 May 06 '19 at 11:11
  • We tried this solution but stuck with some problems. Looks like maven doesn't resolve version variable when I try to build not-full project, but some module (`-pl` switch). `[ERROR] Failed to execute goal on project my-ci: Could not resolve dependencies for project com.core.my:my-ci:pom:MASTER-SNAPSHOT: Failed to collect dependencies at com.core.my:my-server:jar:MASTER-SNAPSHOT: Failed to read artif act descriptor for com.core.my:my-server:jar:MASTER-SNAPSHOT: Could not find artifact com.core.my:my:pom:${dxcore.version} in shared (https://maven.in.mycompany.com/content/repositories/shared)` – turbanoff Sep 16 '19 at 11:30
  • @d2k2 I come to this warning too. So is there any solution? – NanoNova Jan 06 '20 at 05:05
21

You could also use:

$ mvn release:update-versions -DdevelopmentVersion={version}

to update the version numbers in your POMs.

Stefan van den Akker
  • 6,661
  • 7
  • 48
  • 63
Jerry Jin
  • 211
  • 2
  • 2
14

eFox's answer worked for a single project, but not when I was referencing a module from another one (the pom.xml were still stored in my .m2 with the property instead of the version).

However, it works if you combine it with the flatten-maven-plugin, since it generates the poms with the correct version, not the property.

The only option I changed in the plug-in definition is the outputDirectory, it's empty by default, but I prefer to have it in target, which is set in my .gitignore configuration:

<plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>flatten-maven-plugin</artifactId>
   <version>1.0.1</version>
   <configuration>
      <updatePomFile>true</updatePomFile>
      <outputDirectory>target</outputDirectory>
   </configuration>
   <executions>
      <execution>
         <id>flatten</id>
         <phase>process-resources</phase>
         <goals>
            <goal>flatten</goal>
         </goals>
      </execution>
   </executions>
</plugin>

The plug-in configuration goes in the parent pom.xml

Leo Lozes
  • 1,358
  • 1
  • 15
  • 33
3

Use mvn -N versions:update-child-modules to update child pom`s version

https://www.mojohaus.org/versions-maven-plugin/examples/update-child-modules.html

0
<parent>
    <groupId>com.dummy.bla</groupId>
    <artifactId>parent</artifactId>
    <version>0.1-SNAPSHOT</version>     
 </parent>

 <groupId>com.dummy.bla.sub</groupId>
 <artifactId>kid</artifactId>

You mean you want to remove the version from parent block of B's pom, I think you can not do it, the groupId, artifactId, and version specified the parent's pom coordinate's, what you can omit is child's version.

Yu Chai
  • 77
  • 4
0
It worked for me using BOM approach on parent pom.xml: 

My scenario:
 - parent pom.xml 0.0.0.1-SNAPSHOT
 - sub-project1
 - sub-project2 (sub-project1 is a dependency)

<properties>        
    <revision>0.0.0.1-SNAPSHOT</revision>        
</properties>

<groupId>com.example</groupId>
<artifactId>commons</artifactId>
<packaging>pom</packaging>
<version>${revision}</version>
<name>commons</name>
<description>parent module of commons project</description>


<modules>
    <module>sub-project1</module>
    <module>sub-project2</module>
</modules>

<dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <type>pom</type>
            <version>2.6.4</version>
            <scope>import</scope>
        </dependency>

        <dependency>
            <groupId>com.example.commons</groupId>
            <artifactId>sub-project1</artifactId>
            <version>${revision}</version>
        </dependency>
    </dependencies>

</dependencyManagement>

The sub-project pom.xml can inherit ${revision} number from parent and also the actual listed dependency doesn't need to have tag explicitly mentioned

    <parent>
        <groupId>com.example</groupId>
        <artifactId>commons</artifactId>
        <version>${revision}</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <groupId>com.example.commons</groupId>
    <artifactId>sub-project2</artifactId>
    <version>${revision}</version>
    <name>sub-project2</name>
    <description>implement sub-project2 </description>

    
    <dependencies>  
        <dependency>
            <groupId>com.example.commons</groupId>
            <artifactId>sub-project1</artifactId>           
        </dependency>
       
    </dependencies>
Ajay V
  • 523
  • 5
  • 11
0

On Maven 3.8.4 and on a windows machine here is what you have to do to inherit versions from parent pom 1: Create the parent pom as below

          <groupId>com.example</groupId>
          <artifactId>example</artifactId>
          <packaging>pom</packaging>
          <version>1.0-SNAPSHOT</version>
        
          <modules>
            <module>module-1</module>
              <module>module-2</module>
            <module>module-3</module>
          </modules>
        
          <name>example</name>
          <url>https://www.example.com</url>
        
          <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>17</maven.compiler.source>
            <maven.compiler.target>17</maven.compiler.target>
            <spring.boot.maven.plugin.version>2.5.7</spring.boot.maven.plugin.version>
            <spring.boot.dependencies.version>2.5.7</spring.boot.dependencies.version>
            <spring.cloud-version>2020.0.3</spring.cloud-version>
          </properties>

Dependencies that you want to get the child's dependencies version from them come in "dependencyManagement" tag; "scope" and "type" tags are the key to this goal

          <dependencyManagement>
            <dependencies>
              <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.dependencies.version}</version>
                <scope>import</scope>
                <type>pom</type>
              </dependency>
              <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
              </dependency>
            </dependencies>
          </dependencyManagement>

And dependencies you want to be available for each child will come in "dependencies" tag

      <dependencies>
        <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.18.24</version>
          <scope>provided</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <version>2.7.0</version>
          <scope>test</scope>
        </dependency>
    
      </dependencies>
    
      <build>
        <pluginManagement>
          <plugins>
            <plugin>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-maven-plugin</artifactId>
              <version>${spring.boot.maven.plugin.version}</version>
            </plugin>
          </plugins>
        </pluginManagement>
      </build>
   

2: Now let's see the child pom file

<parent>
    <artifactId>example</artifactId>
    <groupId>com.example</groupId>
    <version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>module-1</artifactId>

<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
</properties>

Notice that I don't specify the versions, so I get them from the parent pom

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <scope>runtime</scope>
    </dependency>
</dependencies>