I'm tasked to audit the licenses used in a project we are releasing, which is a Spring Boot multi-module Maven application.
The project is structured with a parent pom.xml declaring the Spring boot BOM:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
And then in one of the submodules (we have 4), which is the actual Web application, we have configured the spring-boot-maven-plugin with repackage task -- this creates a executable JAR of about 31 megabytes.
Running mvn site on a Spring boot project like this, then opening target/site/index.html and click on "Dependency management", we can see a very big list of dependencies provided by Spring Boot. Now, I'm fairly sure that we only use a one-digit quantity of this list (like 9 or 10 libraries), and I can read on the spring-boot-maven-plugin documentation that this only concerns the "provided" scope, as Spring should be treated as a application container.
On the other hand, I'm using the mvn dependency:analyze and mvn dependency:tree goals to check the effectively used stuff, including transitive dependencies. Most of this stuff is not declared in the pom.xml files, as mentioned we have a parent pom that uses the BOM from Spring-boot and then in the single modules we activate dependencies as needed.
My questions:
1) On the legal side, can I assume that all the stuff shown by mvn site for Spring Boot is not the actual list of dependencies used at compile time? Would it be possible to force out of the JAR anything that we are not using? I tried to configure the spring-boot-manven-plugin by using an exclusion list, but the JAR size did not change.
2) how do I programmatically compile a list of dependencies and the attached licenses? I have the feeling that mvn dependency:analyze is the right path but is there a way to poll the License used by any module listed?
Related
We have module that uses DropWizard with Jetty, and it fails on startup with the error: "org/eclipse/jetty/util/thread/ExecutionStrategy$Factory"
java.lang.NoClassDefFoundError: org/eclipse/jetty/util/thread/ExecutionStrategy$Factory
at org.eclipse.jetty.io.SelectorManager.<init>(SelectorManager.java:52)
at org.eclipse.jetty.server.ServerConnector$ServerConnectorManager.<init>(ServerConnector.java:497)
at org.eclipse.jetty.server.ServerConnector.newSelectorManager(ServerConnector.java:229)
at org.eclipse.jetty.server.ServerConnector.<init>(ServerConnector.java:221)
at io.dropwizard.jetty.HttpConnectorFactory.buildConnector(HttpConnectorFactory.java:562)
at io.dropwizard.jetty.HttpConnectorFactory.build(HttpConnectorFactory.java:539)
at io.dropwizard.server.DefaultServerFactory.buildAppConnectors(DefaultServerFactory.java:234)
at io.dropwizard.server.DefaultServerFactory.buildRoutingHandler(DefaultServerFactory.java:194)
at io.dropwizard.server.DefaultServerFactory.build(DefaultServerFactory.java:172)
at io.dropwizard.cli.ServerCommand.run(ServerCommand.java:49)
at io.dropwizard.cli.EnvironmentCommand.run(EnvironmentCommand.java:44)
at io.dropwizard.cli.ConfiguredCommand.run(ConfiguredCommand.java:87)
at io.dropwizard.cli.Cli.run(Cli.java:78)
at io.dropwizard.Application.run(Application.java:93)
There are multiple modules in this project and there are 2 different jetty-io artifacts in the project, one with version: 9.3.20 and 9.4.18 (this is where SelectorManager is located, which tries to use the non-existing interface).
And for some reason it seems like that the older version (9.3.20, which is pulled by another module) gets to be on the classpath, and it tries to use the Factory interface within the ExecutionStrategy interface.
The ExecutionSrategy intervface is within the jetty-util artifact. And there are 2 versions of this artifact as well (9.4.18 and 9.3.19, the newer version does not have this Factory interface within ExecutionStrategy.
The result of mnv:dependency -Dverbose of the module where the error was thrown:
result of mvn command
I dont really know how to tackle this issue, the maven tree looks good, the good dependencies are being used from what I am seeing
Do not mix multiple versions of Jetty at the same time.
It might be a good idea to depend on the jetty-bom to force all jetty dependencies to be a specific version, no matter the transitive dependencies where they are coming from. (directly referenced dependencies will not use bom features)
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-bom</artifactId>
<version>9.4.28.v20200408</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
We are planning to create one spring boot project , which we create as jar file , and this jar we will use as dependency for another spring boot application , point is the first jar must contains the classes we code and its related jar files , is it possible like that ?can any one help us please .
Problem is when i create the jar , only my classes which i coded are packing into jar , not the dependencies of that app
Just use spring-boot-maven-plugin or spring-boot-gradle-plugin depending on your build system. Purpose of these plugins is exactly your use case.
Spring Guides are great place to start exploring: Maven Guide, Gradle Guide.
The only caveat is that you want to exclude tomcat internal container from such shared library:
Maven:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- ... -->
</dependencies>
Gradle:
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
...
}
You can do that by using "maven shade" plugin for creating a Fat jar, also called uber-jar of the parent project, which you want to use in child project. This Fat jar contains the code you have written along with all the dependencies of the project. You can check here for more details : https://maven.apache.org/plugins/maven-shade-plugin/index.html. The Fat jar created will be placed in your local repository.
In your child project, you can use parent project as a dependency by specifying following properties:
<dependency>
<groupId>parent_project_group_id</groupId>
<artifactId>parent_project_artifact_id</artifactId>
<version>parent_project_version</version>
<dependency>
Make sure that you build parent project with maven shade plugin and not with spring boot default plugin. Also, use "clean install" as goal while building the parent project.
I learned Spring via Spring In Action 3 few month ago. I downloaded Spring libraries from official site (list was like in SIA3(aop, asm, aspects, beans ...)), added them to my project and everything worked fine. Now I want to use Maven, but I am getting a lot of errors and sinking in searching what library to add.
I am newby, dont know all Spring dependencies(within it libs) and the question is not about my errors, but about the way to add all Spring libraries to my project via Maven. How do you usually add Spring libs using Maven?
You don't have to download the libraries themselves anymore. That is what Maven is for. (and quite some more, of course)
set up Maven properly
set up Maven in the IDE tool you have (like this)
edit the pom.xml to include what you need, adding the dependencies in the in the dependencies tag.
Maven takes care of resolving the dependencies of the specified packages. If a package depends on other packages, it will do it for you. You only have to specify the packages you directly need
For example
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
<version>2.5.6</version>
</dependency>
You can easily find the packages using Google, and searching for "maven repository "
Avoiding version clashes
Also, as Bart mentioned, the common way of having Spring in the pom.xml - as it has way too many versions, and clashes can occur - is through a common property specifying the version for all Spring components. (Based on this answer)
Specify the property in the properties tag:
<properties>
<spring.version>3.0.5.RELEASE</spring.version>
</properties>
Then use it in the dependencies like this:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
Be careful to use it for ALL components to avoid version clashes. (of course, issues mught still occur, bz having different libraries reference spring too, but that is another story in its own.)
Side note
Keep in mind note that Maven projects use specific directory layout. When I first started using maven for my own projects, first I created a new blank one, and played around with it, before I began migrating my older projects to use maven. Believe me, it pays off.
Add spring artifacts to your pom.xml file. For example
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.2.4.RELEASE</version>
You can find more artifact info here
http://mvnrepository.com/
HERE you can find the dependencies as per your requirement. Just click on the dependency and inside click on the latest release, scroll down there is your code inside the <dependencies> Your required dependency and version</dependencies>.
Just copy the XML code and paste it in your pom.xml file.
I have a multimodule maven project, where module share dependencies. By share I mean use the same dependencies. However each module declares dependencies itself. To keep sanity (yeah, maven, sanity, I know), and to have all modules using the same version of dependencies, parent pom declares properties with version numbers:
<properties>
<dependency1.version>1.0-SNAPSHOT</dependency1.version>
<dependency2.version>1.1-SNAPSHOT</dependency2.version>
</properties>
and all modules use that like:
<dependency>
<groupId>group</groupId>
<artifactId>dependency1</artifactId>
<version>${dependency1.version}</version>
</dependency>
I'm quite happy with this setup, as it allows me to change dependencies versions in 1 place.
Now I have a bunch of dependencies that I maintain myself. Release of those is automatic and very simple, basically:
mvn release:prepare release:perform -B
now I want to automate further and in the main project I run:
mvn versions:update-properties
(basically I also run: "mvn versions:use-releases" to change usual dependencies if needed, but it's out of the scope of this question).
After this update-properties run, properties in my main projects pom point to releases (which is good). However if my modules use properties to define versions of other dependencies and those projects have newer versions available, those properties are also changed.
Is there any way to limit damage from update-properties? versions:use-release takes includes property, so I can use it only on mine artefacts. Cannot find anything similar for update-properties.
I can revert all poms besides parent one and commit/push only that, but it doesn't seem elegant.
It sounds that you didn't understand the concept of maven.
In such circumstances you should use dependencyManagement in the parent pom like the following:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
...
</dependencies>
</dependencyManagement>
In you modules you just use a dependency like this:
<dependencies>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
</dependency>
...
</dependencies>
The important step is not to define the version. In this case the version will be used which is defined by the dependency management block. So you don't need to define properties etc. and furthermore you have a single point where you can define and change the dependencies in particular the versions.
Apart from that it's possible to limit the properties which will be changed defining it on the command line on the version:update-properties call.
I am new to Maven and am setting up my first maven project. I am also creating some maven assets in the form of some poms that can be inherited from or used as dependencies in any future projects as well. I want to group dependencies together and to be able to selectively add them to a project as needed.
I read this article on pom best practices. I like the idea of grouping related dependencies together into poms and then adding the pom as a dependency to a project as needed. This approach works great for compile scoped dependencies. However it fails for provided scoped ones since as transitive dependencies, they get omitted.
Here's an example of what I mean: Lets say I group together web dependencies for my projects into a web-deps pom.xml. These include compile scoped spring framework dependencies and also a provided scoped javaee one:
<modelVersion>4.0.0</modelVersion>
<groupId>com.xyz</groupId>
<artifactId>mvn-web-deps</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>javaee</groupId>
<artifactId>javaee-api</artifactId>
<version>${javaee.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
I then add this pom as a dependency in another project:
<modelVersion>4.0.0</modelVersion>
<groupId>com.xyz</groupId>
<artifactId>project-a</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependency>
<groupId>com.xyz</groupId>
<artifactId>mvn-web-deps</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>pom</type>
</dependency>
The dependencies in mvn-web-deps now become transitive. Since the dependency reference above is compile scoped, the provided transitive dependency gets omitted.
I want to avoid adding them to the dependency section of a parent since there can only be one parent and a project may need only some of these dependency groups, not all. I can perhaps add them to the dependencyManagement section, but then I will have to redeclare each dependency (sans the version) in each child project.
What is the correct/better way of grouping dependencies while avoiding the issues like above?
The short answer to your question is that you should only include 'provided' dependencies locally where the code requires it to compile, but not in parent pom.xml or other structures. Indicating that you have a 'provided' dependency in global pom.xml is non-sense for maven, because it does not need it to compile in such pom.xml.
Here is the long answer:
When I started using Maven, I had the same idea of trying to group artifacts and dependencies into pom.xml modules hoping they would be useful in the future. Now, that I have a bit more experience, I got to understand that it is a complete waste of time. For me, this was form of over-engineering.
I have learned to split my big projects into separate modules, each in their own subversion repository. I am including dependencies as necessary for each local module in their pom.xml. I release versioned tags of each module as I am coding and as necessary (i.e., when tested and stable).
I build my big projects by creating a separate maven project with its own pom.xml and import my modules as dependencies. From time to time, I update the module's version in the dependency when I have made a release. Then, I let maven do the job of pulling whatever it has to pull, transitively of not, when compiling/releasing the big project.
Maven allows all sorts of complex constructions and hierarchy between pom.xmls, but IMHO this feature creates unnecessary mess and complexities. So far it has not proved to be a real benefit for me. At the beginning, I was hoping that compiling one pom.xml would compile the rest properly in a cascading way. I did get some result, but what a mess to maintain in all the global pom.xml.
Releasing my module's artifacts separately and building my project on these releases has saved me so much time that I can only recommend it. In total, I have less pom.xml to maintain and they are also less complex. For the same final result...
So, if your only reason for building global/structural pom.xml is a hope to save time, I recommend abandoning this idea... Separate code in separate projects, release and THEN compile globally.
I concluded that Maven was not designed for this kind of use-case. I ended up having a parent pom.xml with all the libraries I use added to its <dependencyManagement> section. Any new projects/modules that I create have their pom.xml inherit from the parent pom.xml and add each dependency they need to their own <dependencies> section, minus the version. This scheme allows me to manage the versions for the libraries that I use and the respository declarations they need at a single place. Another advantage (over trying to create dependency bundles somehow) is that this gives more fine-grained control over the libraries added to child poms - only the dependencies that are actually needed are added.
Provided-scope dependencies are indeed inherited from parent POM, but NOT from POM defined as dependencies and I consider that a Maven weakness.
Given that Maven has also difficulties in adding modules as dependencies across module hierarchies, I can't say Maven is a sophisticated tool to manage multi-module projects. Maven expects a strict single-rooted hierarchy that is only suitable for the simplest projects.