1
votes

I want to build jar file library and not include dependencies, as they will be in class path of application which will use this library. I use maven scope - provided for that and all dependencies are excluded but few still left. I found they come from spring-boot-starter-webflux. Why it this? And what should I do to get rid of them?

Here the dependency example

<dependencies>
    <!-- Nevertheless provided scope some jars from this dependency
     are in compiled jar file. Why ? -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
        <scope>provided</scope>
    </dependency>
</dependencies>

Sample project with just this one dependency is on https://github.com/pavelmorozov/MavenProvidedTest/blob/master/pom.xml

Empty compiled project jar have 5+ megabytes size.

Update After JF Meier suggestion, I tried mvn dependency:tree and found two libraries with scope compile

[INFO]    +- org.springframework.boot:spring-boot-starter-reactor-netty:jar:2.1.3.RELEASE:provided
[INFO]    |  \- io.projectreactor.netty:reactor-netty:jar:0.8.5.RELEASE:compile
[INFO]    |     +- io.netty:netty-codec-http:jar:4.1.33.Final:compile
[INFO]    |     |  +- io.netty:netty-common:jar:4.1.33.Final:compile
[INFO]    |     |  +- io.netty:netty-buffer:jar:4.1.33.Final:compile
[INFO]    |     |  +- io.netty:netty-transport:jar:4.1.33.Final:compile
[INFO]    |     |  |  \- io.netty:netty-resolver:jar:4.1.33.Final:compile
[INFO]    |     |  \- io.netty:netty-codec:jar:4.1.33.Final:compile
[INFO]    |     +- io.netty:netty-codec-http2:jar:4.1.33.Final:compile
[INFO]    |     +- io.netty:netty-handler:jar:4.1.33.Final:compile
[INFO]    |     +- io.netty:netty-handler-proxy:jar:4.1.33.Final:compile
[INFO]    |     |  \- io.netty:netty-codec-socks:jar:4.1.33.Final:compile
[INFO]    |     \- io.netty:netty-transport-native-epoll:jar:linux-x86_64:4.1.33.Final:compile
[INFO]    |        \- io.netty:netty-transport-native-unix-common:jar:4.1.33.Final:compile
...
[INFO]    +- org.springframework:spring-webflux:jar:5.1.5.RELEASE:provided
[INFO]    |  \- io.projectreactor:reactor-core:jar:3.2.6.RELEASE:compile
[INFO]    |     \- org.reactivestreams:reactive-streams:jar:1.0.2:compile

And for example I see one of POM files

  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-reactor-netty</artifactId>
  <version>2.1.3.RELEASE</version>
  ...
  <dependencies>
    <dependency>
      <groupId>io.projectreactor.netty</groupId>
      <artifactId>reactor-netty</artifactId>
      <version>0.8.5.RELEASE</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>

Now I still not get why other Spring Boot included libraries not override scope to compile. Does it means this two libraries build wrong or they build this way for some reason? And I still not clear how to remove in simple way dependencies that seems have override scope?

I tried to put version number in my POM dependency - but this have no effect - same jars included in compiled project jar:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
    <version>2.1.3.RELEASE</version>
    <scope>provided</scope>
</dependency>

Update about parents

Parent pom file spring-boot-starter-parent not contains any dependencyManagement section, but have one more parent - spring-boot-dependencies - and it does have dependencyManagement section but scope compiled there is not provided. Some of dependencies have scope import though. I not understand could this import scoped dependencies have effect in my case. Some samples from here:

<dependencyManagement>
    <dependencies>
        ...
        <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-reactor-netty</artifactId>
           <version>2.1.3.RELEASE</version>
       </dependency>
       ...
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-bom</artifactId>
            <version>${reactor-bom.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
       ...
    </dependencies>
</dependencyManagement>

The part of content of spring-boot-starter-reactor-netty i posted here in previous update.

Update after Andy Wilkinson answer just to clarify - such dependencies are not included in jar, seems spring boot maven plugin do its work in different way here:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <scope>provided</scope>
</dependency>
3

3 Answers

2
votes

A Spring Boot fat jar is intended to contain everything that's required to run the application. You can't use -jar and -classpath at the same time when launching the JVM, so that means that the jar needs to contain provided dependencies as well as there's no other way for them to get onto the classpath.

This behaviour is described in the documentation for Spring Boot's Maven Plugin where it says the following:

The example above repackages a jar or war that is built during the package phase of the Maven lifecycle, including any provided dependencies that are defined in the project.

If you don't want your application's jar to have any dependencies packaged inside it, i.e. you want it to be a normal jar rather than a fat jar, then you probably do not want to use Spring Boot's Maven plugin to build it. If you remove it from your sample project's pom.xml file and then build it, the resulting jar has the following contents:

$ unzip -l target/MavenProvidedTest-0.0.1-SNAPSHOT.jar 
Archive:  target/MavenProvidedTest-0.0.1-SNAPSHOT.jar
  Length      Date    Time    Name
---------  ---------- -----   ----
      329  02-22-2019 11:33   META-INF/MANIFEST.MF
        0  02-22-2019 11:33   META-INF/
        0  02-22-2019 11:33   META-INF/maven/
        0  02-22-2019 11:33   META-INF/maven/io.spring/
        0  02-22-2019 11:33   META-INF/maven/io.spring/MavenProvidedTest/
        1  02-22-2019 11:33   application.properties
     1403  02-22-2019 11:33   META-INF/maven/io.spring/MavenProvidedTest/pom.xml
      101  02-22-2019 11:33   META-INF/maven/io.spring/MavenProvidedTest/pom.properties
---------                     -------
     1834                     8 files

If you want some but not all of the dependencies to be included, then you could continue to use Spring Boot's Maven Plugin and exclude some dependencies instead.

1
votes

It is possible that the parent pom has a dependencyManagement section that overwrites scopes/versions.

0
votes

From your question I understand that you need a thin executable jar. For you may use spring-thin-launcher plugin. It will exclude the dependencies to be packaged as part of the jar but will download from maven during first run or you may provide your own local repo where all the jar files can be found.

For details refer to this tutorial