Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spring-boot-maven-plugin includes "provided" scope dependency in JAR #413

Closed
ghost opened this issue Feb 28, 2014 · 28 comments
Closed

spring-boot-maven-plugin includes "provided" scope dependency in JAR #413

ghost opened this issue Feb 28, 2014 · 28 comments

Comments

@ghost
Copy link

ghost commented Feb 28, 2014

With JAR packaging & spring-boot-maven-plugin, dependency with scope "provided" ends up in repackaged JAR.

I'm under impression that this should not be the case?

Should ResolutionScope be something else in RepackageMojo?

@dsyer
Copy link
Member

dsyer commented Feb 28, 2014

Not sure. What's the use case exactly? Where would the dependencies come from at runtime?

@ghost
Copy link
Author

ghost commented Feb 28, 2014

The use case is that I use embedded LDAP server (ApacheDS) for development and testing purposes in my project. For this I need to use dependency

    <dependency>
      <groupId>org.apache.directory.server</groupId>
      <artifactId>apacheds-all</artifactId>
      <version>1.5.5</version>
    </dependency>

However this is something that should not end up in JAR used in production environment.

@philwebb
Copy link
Member

The packaging of provided scoped jars is intentional. The reason for this is that many developers are used to adding things like servlet-api as provided. Since there won't be a servlet container to actually "provide" the dependency we package it inside the JAR.

It also allows us to create executable WARs, where provided items are located when you run java -jar but ignored if the war is deployed in the usual way.

Could you use the test scope for your use case?

@dsyer
Copy link
Member

dsyer commented Feb 28, 2014

@philwebb: I agree that it's a bit of an abuse of notation and I can see that it was intentional from the source code, but I think this is a weakness in Maven that there is no way to do this explicitly, and maybe we should be open to allowing users to work around it in some way (if not this then something else).

@sekotin: I'm still not quite clear why you need to use provided scope either, or what harm it does having the embedded jars in your production archive. Can you explain a bit more?

@philwebb
Copy link
Member

@dsyer I did think about adding an exclude parameter to supply additional filtering, but since you always have the <optional>true</optional> or test scope alternatives I didn't think it was worth it.

@dsyer
Copy link
Member

dsyer commented Feb 28, 2014

@sekotin: does optional=true work?

@ghost
Copy link
Author

ghost commented Feb 28, 2014

@philwebb: I understand your example about servlet-api. Maven JAR plugin has filtering options (excludes/exclude) but when I tried that it did not work. I'm not sure if this is because of repackage. I'm currently using test scope but obviously with that I cannot use spring-boot:run in development environment

@dsyer: Having the JARs in my production archive does not do any harm but I want to keep it clean. No code should be in the archive that is not supposed to be run in production. I will try the option=true and see how it affects. I thought that using provided scope I could leave dev JARs out of the archive but still use spring-boot:run in my development environment by (somehow?) explicitly pointing to dev JARs.

Thank you for your comments so far

@wilkinsona
Copy link
Member

@sekotin Another option could be to use a profile for your development-only dependencies

@philwebb
Copy link
Member

@sekotin The excludes/exclude setting on the JAR plugin will only effect contents in the original jar. We ignore it when adding the nested JARs.

I'm currently using test scope but obviously with that I cannot use spring-boot:run in development environment

Are you saying that you would want provided scoped items with spring-boot:run but not when packaged? Currently the run task is designed to be as close as possible to the actual packaged code.

@ghost
Copy link
Author

ghost commented Feb 28, 2014

I'm not sure what would be the ideal setup. What I would like is

a) by default not to include dev JARs in production archive
b) means to run the archive in development environment without any hacks

I already tried profile for development-only dependencies, maybe it is the way to go although I'm not a big fan of Maven profiles

@philwebb
Copy link
Member

Did

  <dependency>
      <groupId>org.apache.directory.server</groupId>
      <artifactId>apacheds-all</artifactId>
      <version>1.5.5</version>
      <optional>true</optional>
    </dependency>

Work for you? If not I could tweak the maven plugin so that provided dependencies get included but optional ones do not.

@ghost
Copy link
Author

ghost commented Mar 3, 2014

Using optional: true my "dev JARs/dependencies" still end up in final archive.

Profiles don't work here (without hackish configuration) because I need "dev JARs" when the tests are run. E.g. I cannot create dev profile with dev JAR depencency since then I could not create a final production package using mvn package where the tests are run (and failing because of missing dependency).

I'm still trying to figure out what would be the correct definition for "provided" scope in this case. For now I'm using scope test and run my application in dev environment using Eclipse.

@dsyer
Copy link
Member

dsyer commented Mar 3, 2014

We could certainly tweak the plugin so it ignores optional dependencies during repackaging. I'm not sure whether that makes a lot of sense though: optional dependencies don't really have a meaning for a normal Maven packaged application (only for a library used by others), so we are ascribing a meaning where there was none. If you think that's less "hackish" (sic) than a dev profile you are welcome to your opinion, but I'm not so sure. I don't see what's wrong with using scope=test anyway, since your stated goal is to be able to run tests during the package phase. If you want to "mvn spring-boot:run" your app locally as well, I can see that is a useful thing to be able to do, and that might be the ideal opportunity for a Maven profile (and a Spring profile to match it probably, or maybe just some autoconfiguration?).

@ghost
Copy link
Author

ghost commented Mar 3, 2014

I think I'm quite ok now using the test scope. However thinking more of this I believe "provided" scope should mean that the dependencies won't end up in final archive but are provided by classpath option when running the JAR.

Anyway, thanks for your input and work

@r0nin
Copy link

r0nin commented Mar 4, 2014

Well i actually had exactly the same issue, and i didnt really understood why the plugin packaged my "provided" things. Until i really tried what you wrote in your last comment: "... but are provided by classpath option when running the JAR". The ugly or better the consistent thing about it is: there is no way to do that. You cannot add things to an executable JAR. As soon as you use -jar option the JVM will completely ignore your classpath. And its probably correct to do so. Because by using an executable JAR you have choosen to live inside your own bubble.

On the downside there are in fact things i depend on which are not even available as Maven dependencies and i cannot "redeploy" these things in a completely other version in my own bubble. I have to use the environment on that production machines. So at the end i had to rethink, forget the executable JAR option at all and use the inflated approach which should be better supported in docs by the way ;)

@dsyer
Copy link
Member

dsyer commented Mar 4, 2014

Not sure what you mean by "the inflated approach". The PropertiesLauncher has the virtue, I believe, of allowing the classpath to be a mixture of nested JARs (in the "java -jar ..." target archive) and JARs on the file system (or nested in other archives). It is documented, but please feel free to add more.

@r0nin
Copy link

r0nin commented Mar 4, 2014

sorry. i meant the exploded approach. Thanks for the hint to the PropertiesLauncher.

@ghost
Copy link
Author

ghost commented Mar 5, 2014

I tried using the following configuration but the application does not find the correct classes. Anything I might be missing here?

        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <arguments>
                    <argument>--spring.profiles.active=dev</argument>
                </arguments>
                <folders>
                    <folder>C:/Users/username/.m2/repository/org/apache/directory/server/apacheds-all/1.5.5</folder>
                </folders>
            </configuration>
        </plugin>

@dsyer
Copy link
Member

dsyer commented Mar 5, 2014

I think "folders" only adds the directory to the classpath, not the jars inside it. You could add jars as "folders" though probably?

@koscejev
Copy link

koscejev commented May 29, 2018

Sorry to resurrect this, but I stumbled upon this closed issue 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 like 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.

@wilkinsona
Copy link
Member

@koscejev That's an interesting suggestion, thanks. I'd you like us to consider it, can you please open a separate issue so that it doesn't get forgotten in this closed issue?

@koscejev
Copy link

@wilkinsona no problem: #13289

@jeacott1
Copy link

jeacott1 commented Sep 26, 2019

I wound up here for a slightly different reason. I have a standalone primary spring boot executable jar, and a plugin jar (also with a spring-boot parent starter) that depends on the primary as provided scope, and is dynamically loaded at runtime.
I wanted to include the build-info in the plugin jar file so I thought I'd just use the spring-boot-maven-plugin build-info goal, but alas my plugin includes everything in the primary project as well as all its own dependencies. the docs for the build-info dont say anything about repackaging or otherwise affecting the build, so I'd thought (naively) that it wouldn't. alas I was wrong. :(
imo violating a basic tenant of a basic maven directive isn't a good idea at all. you could very easily wind up with multiple versions of jars in the same env if not very careful.

@wilkinsona
Copy link
Member

you could very easily wind up with multiple versions of jars in the same env if not very careful

I don't believe that can happen. Can you please explain how it could?

@wilx
Copy link

wilx commented Nov 5, 2019

Here is a scenario that I have. I have dependencies that have dependencies like javax.annotation:javax.annotation-api and other that already use jakarta.annotation:jakarta.annotation-api. These two overlap and I would like to know which one is actually used so, ideally, I would be able to declare one as provided and use the other internally.

@wilkinsona
Copy link
Member

Those two dependencies contain the same classes so you should exclude one rather than using provided scope. In Boot 2.2, we moved to the Jakarta-named artifacts so I'd recommend jakarta.annotation:jakarta.annotation-api there. If you're using Boot 2.1, the javax-named artifact is probably the one to keep.

@vananiev
Copy link

vananiev commented Mar 10, 2020

I fix maven runtime dependency inclusion (!not provided, this is related problem) with maven profiles (I add release and debug profiles).

@chanseokoh
Copy link

chanseokoh commented Aug 17, 2020

As a workaround, one could use Spring Boot's <excludes> to exclude dependencies. However, note that it still includes all the transitive dependencies, so you should identify and list them too. (See #22981 and #13289 for more details.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants