Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maven dependencyManagement: inherit dependency version from parent

Tags:

maven

maven-3

I want my dependency in dependencyManagement block to inherit a version from spring-boot-parent's dependencyManagement block, but add exclusion to it, so that I don't need to specify that exclusion in each of child modules.

My parent pom inherits from spring-boot-parent:

  <artifactId>my-parent</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
    <relativePath/>
  </parent>
  <dependencyManagement>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>???</version>
        <exclusions>
          <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-logging</artifactId>
          </exclusion>
        </exclusions>
      </dependency>
  </dependencyManagement>

child pom inherits my-parent:

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-log4j2</artifactId>
    </dependency>
  </dependencies>

I tried several approaches:

  • When I replace ??? with ${parent.version}, in child module this version is resolved to be my-parent's version: 1.0.0-SNAPSHOT, which is incorrect.

  • When I replace ??? with ${parent.parent.version}, maven breaks, as it doesn't support such properties

  • I can fix ??? to be 2.0.1.RELEASE and this will work fine, but if I update the version of spring boot, I have to remember to update the version of this dependency also, which is non-intuitive

  • I cannot extract 2.0.1.RELEASE as a property in my-parent and use that property as parent version, as maven does not support that.

  • I could've used property with value 2.0.1.RELEASE inherited from spring-boot-parent pom, but there is none such property, as far as I can see.

Is there a nice way to achieve what I want?

like image 940
zbstof Avatar asked May 31 '18 08:05

zbstof


1 Answers

See Possible to have the parent version as Property to give to the children? - the version used to declare your parent can't be repurposed in a way that says "make this reference fixed to mean its interpretation at this point in the graph". Strings are strings and placeholders are placeholders; there's no built-in facility to have some kind of in-between thing. If the parent uses a property to define a dependency version you can reference that property; if it uses a fixed string (as in your case) then you'll need to repeat something in order to define an exclusion. As referenced in the linked question, a common way is something like this:

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.1.RELEASE</version>
  </parent>
  <properties>
    <spring.boot.version>2.0.1.RELEASE</spring.boot.version>
  </properties>
  <dependencyManagement>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>${spring.boot.version}</version>
      <exclusions>
        ...

You still have to repeat the value in two fields -- so you have to make very sure that you always keep those in sync (parent version and property).

However, the increasingly-popular way to manage this is to declare those versions in a BOM (a "bill-of-materials" pom with the specific purpose of keeping a set of components aligned). Then the dependencyManagement stuff can be imported instead of inherited. Spring Boot has been doing this for a while now; in fact the parent in your example doesn't actually declare the dependencies itself, they come from a different artifact. So instead of inheriting from the parent, you could do something like this (I might have the sequence of these backwards -- I can't remember whether first or last wins):

  <properties>
    <spring.boot.version>2.0.1.RELEASE</spring.boot.version>
  </properties>
  <dependencyManagement>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-dependencies</artifactId>
      <version>${spring.boot.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
      <version>${spring.boot.version}</version>
      <exclusions>
        ...

... now, if there are other reasons (beyond just dep mgmt) you wanted to inherit from spring-boot-starter-parent then this won't really help your problem; you'll still need to duplicate. But I suspect that as your project matures you'll want to have a parent of your own devising anyway.

like image 71
Zac Thompson Avatar answered Nov 09 '22 20:11

Zac Thompson