spring-boot
spring-boot copied to clipboard
Allow provided and optional dependencies to be exclude when building a uber jar with Maven
I stumbled upon #413 when trying to resolve exactly the same problem. We're using some provided
artifacts and don't want them to end up in the final deliverable. This is exactly 100% according to maven definition of provided
scope (i.e., available on the compile and test classpaths, but not at runtime).
Case in point, recommended usage of Lombok annotations is via provided
scope. But that's just one example. We're using many other dependencies that are essentially build-time dependencies, not runtime ones. (And not just annotations that can be wired via annotationProcessorPaths
property mentioned in #10539.) Trying to switch to spring-boot-maven plugin, but this results in huge repackaged jar containing a lot of unnecessary junk due to transitive dependencies of provided artifacts.
TLDR: I'd really appreciate an includeProvidedScope=false
option (similar to includeSystemScope
) for people who know what they are doing, so that I can configure this in just one place for all projects and don't need to duplicate a list of dependencies as excludes in the plugin config.
This is exactly 100% according to maven definition of provided scope (i.e., available on the compile and test classpaths, but not at runtime).
That's the Maven textbook definition but it does not apply to what the repackage
goal does, see the documentation. I am not against providing more flexibility in that area but I'd like we take a step back and we look at your use cases first. Given that provided
isn't transitive and that you add them in a project that generates "an app" (since the repackage
goal is involved), I'd like to understand what is flagged as provided
and why.
Can you share more details please?
One other example (besides annotations) is we have dependencies with provided
scope, but unpack and process the contents via some custom build step, generating some code based on the contents, or using some parts of the dependency statically, etc.
Although some parts could probably be streamlined to not use provided
dependencies, it would definitely take a lot of time to make so many changes to the existing build. So even in cases where it's possible to change this, we would still prefer to do gradual changes instead of one big rewrite of the whole build.
but unpack and process the contents via some custom build step
You can unpack and process dependencies with the maven-dependencies-plugin
(they don't need to be added to your dependencies). Perhaps they shouldn't be managed there at all and the result of the post-processing should be made available as a dedicated artifact.
The reason why I insist so much is because it's part of the user experience you get with Spring Boot. Anything that is required that way means that it's harder for you to run the application from your IDE.
Perhaps they shouldn't. However, this is reality of the build we have right now and it works in maven with every other plugin and worked like this before for every project we have. Perhaps we could change that, but that would take some time and would not be done in a day.
Since you're mentioning IDE, the current build works perfectly in IntelliJ IDEA and we aren't really using other IDEs, so I don't know how other IDEs handle this.
We've discussed at the team call and given that provided
dependencies are clearly identified as being included in a repackaged app, we're not keen to add this option. If you want to pursue with your build setup, you can easily create a custom layout that excludes the dependencies you don't want. There is a sample that shows you how to get a custom layout and Layout.getLibraryDestination
is the method you should override.
pretty silly I'd say
we are running into the same issue where spring-boot plugin pulling in the provided scope 'javax.ws.rs-api' which requires jersey-common at runtime
At the same time we str also using the thin boot, but need the option to switch to fat jar at build time, this means we need 2 layout factories. Spring boot plugin bails with java.lang.IllegalStateException: No unique LayoutFactory found
The layout same sample is not trivial ( sorry about my ignorance), not able to get it working yet. if anyone has already implemented the customer factory, I would like to have a look
Also note: thin-boot does not include provided scope, so I am convinced that spring-boot-plugin violates maven spec/convention and best to provide an option for user to disable provided scope inclusion
i am able to get custom layout working and use 2 maven profiles, one build by default with thin boot and another one with activation
<profile>
<id>thinjar</id>
<activation>
<property>
<name>!fatjar</name>
</property>
</activation>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot.experimental</groupId>
<artifactId>spring-boot-thin-layout</artifactId>
<version>${thin.boot.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
<profile>
<id>fatjar</id>
<activation>
<property>
<name>fatjar</name>
</property>
</activation>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<dependencies>
<dependency>
<groupId>com.xxxx.yyy</groupId>
<artifactId>mylayout</artifactId>
<version>${mylayout.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
quite complex. But it works
Using configuration exclusion seems to be a much simpler solution. Not sure whether this fits all your other use cases, though.
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
Not sure why that's off-topic. It appears to be a reasonable solution.
Agreed. I've unhidden it.
Bad news: <excludes>
excludes only a specific artifact, but includes all its transitive dependencies!
@brianwhu exclude
works for single dependency only; any transitive still packaged
I wound up here because I was wondering why Spring Boot packages lombok into my fat jar. Excluding artifacts individually may be okay in some cases, but configuration to opt-out of packaging all provided-scope artifacts sounds like a good idea to me. Explicit excludes are simply not maintainable.
Found a far more painful annotation-processing example: querydsl-apt
. If you're using the standard <scope>provided</scope>
method you have to exclude all this from the package:
<exclude>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
</exclude>
<exclude>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-codegen</artifactId>
</exclude>
<exclude>
<groupId>com.mysema.codegen</groupId>
<artifactId>codegen</artifactId>
</exclude>
<exclude>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
</exclude>
<exclude>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
</exclude>
<exclude>
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
</exclude>
The following hidden comments (https://github.com/spring-projects/spring-boot/issues/13289#issuecomment-498153907, https://github.com/spring-projects/spring-boot/issues/13289#issuecomment-519075075) marked as off-topic seems to be very informative and vital for those who would like to exclude provided
-scoped dependencies as a workaround.
@brianwhu
exclude
works for single dependency only; any transitive still packaged
Bad news:
<excludes>
excludes only a specific artifact, but includes all its transitive dependencies!
I do not understand why someone has hidden such helpful information as off-topic, but I hope this comment does not get hidden as well. If I were the repo maintainer, I would not hide them.
@chanseokoh the issue tracker is not the right place to have such conversation. There is a section with some examples that shows you what the plugin does at the moment and how to configure it to do so. If those are not giving you enough information, feel free to raise a separate issue or, better yet, create a PR to improve the documentation.
Filed #22981 that using <excludes>
still includes all the transitive dependencies. :disappointed:
X-ref: #16563 about a potential solution (issue still open) to the issue that <excludes>
still pulls in all the transitive dependencies.
We've add a few reports around dependency exclusion for the repackage goal with Maven. The fact transitive artifacts are not filtered out is annoying and certain arrangements require a large number of artifacts to be defined.
Reopening because we think there's a good use-case for this with annotation processors. See also this comment.
@philwebb As I was the one that made the comment that resulted in the re-opening of this ticket, I'll attempt to implement the changes required. Thank you for reconsidering the previous decision that resulted in the closing of this ticket :)
Thanks very much, @pgerhard. I’ll assign the issue to you as an indication that you intend to work on it. Please let us know if you have any questions.
We should keep #25403 in mind when working on this.
Is someone working on this issue or any update ? Unfortunately, I still am facing problems with exclusion (with provided scope) or wildcards.
@pgerhard @wilkinsona
It has been several months since we've heard from @pgerhard so I doubt that anyone's working on it. I'll update the issue's assignment to reflect that.
Is there any latest update to this issue?
@Gyanaranjan1993 Nothing beyond what you can see in the issue.
Oh my god! I just fund this issue...
I was debugging for hours and and was questioning my sanity.
This is really bad, I cannot think of any valid reason why an optional dependency should be packed in the spring boot fat jar. I can see a point for provided scope because of the fat jar thing but it still is a violation of the maven spec/convention so there should be a big, prominent warning in the README regarding the current default behavior.
a violation of the maven spec
No it isn't. An optional dependency is one that this project uses for build/deploy, but if you depend on this project then it's not included by default.
Building a fat jar is for deploying this project. Nothing else should be using the fat jar as a dependency.
If optional dependencies weren't included in the build, there would be no point adding them to the pom in the first place, So why are you if you don't want them?
Yes it is a violation. please read the official maven docs:
Optional Dependencies
Optional dependencies are used when it's not possible (for whatever reason) to split a project into sub-modules. The idea is that some of the dependencies are only used for certain features in the project and will not be needed if that feature isn't used. Ideally, such a feature would be split into a sub-module that depends on the core functionality project. This new subproject would have only non-optional dependencies, since you'd need them all if you decided to use the subproject's functionality.
However, since the project cannot be split up (again, for whatever reason), these dependencies are declared optional. If a user wants to use functionality related to an optional dependency, they have to redeclare that optional dependency in their own project. This is not the clearest way to handle this situation, but both optional dependencies and dependency exclusions are stop-gap solutions.
https://maven.apache.org/guides/introduction/introduction-to-optional-and-excludes-dependencies.html
I would agree with you if we would be talking about the provided
scope