Maven: Package "brother" projects - maven

I am working on a big set of projects strongly related to each other and looking for a way to reduce to minimimun the maintenance overhead using a good maven configuration.
One of the scenarios which I am currently working on is a set of several small projects inside the same "company project", most of them depending on the others, with a big list of external dependencies in each one.
In order to make it cleaner I created a parent pom, set all of them as modules and created a big list of dependencies inside the parent's dependencyManagement section allowing me to remove most of the version tags inside the project poms.
The next stage for me is to reduce the amount of resulting jars by making use of some plugin, such as one-jar or assembly, in oder to get a signle jar from one of those projects containing all the others inside. However, this led me to having an enourmous jar with tons of external libraries inside, most of them already provided by the running environment.
I know that adding the <scope>provided</scope> tag to the declaration of external dependencies would do the job, but I would like to avoid having dozens of these tags in my poms.
So the questions are:
Is there any way to define a default scope, so I can use compile scope only in the libs which I want included?
Then, instead of having this:
<dependencyManagement>
<dependency>
<groupId>any.external</groupId>
<artifactId>lib</artifactId>
<version>1.0</version>
<scope>provided</scope> <!--Skip Inclusion-->
</dependency>
<dependency>
<groupId>any.external</groupId>
<artifactId>cool-lib</artifactId>
<version>1.0</version>
<scope>provided</scope> <!--Skip Inclusion-->
</dependency>
<dependency>
<groupId>another.external</groupId>
<artifactId>lib</artifactId>
<version>1.0</version>
<scope>provided</scope> <!--Skip Inclusion-->
</dependency>
<dependency>
<groupId>my.company</groupId>
<artifactId>some-dependency</artifactId>
<version>1.0</version>
</dependency>
</dependencyManagement>
I could have this (note that the difference will come when we have only 10 internal projects to include, but more than 100 external libs):
<dependencyManagement>
<dependency>
<groupId>any.external</groupId>
<artifactId>lib</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>any.external</groupId>
<artifactId>cool-lib</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>another.external</groupId>
<artifactId>lib</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>my.company</groupId>
<artifactId>some-dependency</artifactId>
<version>1.0</version>
<scope>compile</scope><!-- Include It! -->
</dependency>
</dependencyManagement>
Or better: Maybe I'm skipping something and there is already a way to tell maven: "Include only the jars generated within the current project"?
Remember that all modules are "brothers", included as modules of the same parent, and compiled at the same time.
Many thanks in advance!
Carles

Related

Spring boot 2.1.7 having tomcat-embed-core conflit

I am migrating existing Spring project into Spring boot.unable to run spring boot application its showing following error.
The error log says there is a conflict on tomcat-embed-core.
In eclipse Dependency hierarchy of porm.xml is given below
i exclude the maven architect ,and try to run the application its showing following error
porm.xml
<modelVersion>4.0.0</modelVersion>
<artifactId>MyService</artifactId>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
<!-- 2.1.3.RELEASE -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<springframework.boot.version>2.1.7.RELEASE</springframework.boot.version>
</properties>
<name>MyService</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.sybase.jdbc3.jdbc</groupId>
<artifactId>jconn3</artifactId>
<version>${jconn3.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-juli</artifactId>
<version>${tomcat.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>${tomcat.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
what was wrong in this porm.xml
Where is
${tomcat.version}
defined?
That version probably does not match the tomcat version that auto magically is included with spring boot items.
And thus the conflict.
Go here:
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web/2.1.7.RELEASE
And start following the COMPILE dependencies, and you'll find the versions that are auto included with 2.1.7.RELEASE. and you have to alter the other includes that are overwriting the springboot auto include tomcat versions.
Again, follow the COMPILED dependency trail.
So below is what you should find by crawling the COMPILED dependency trail (from immediately above in my answer)
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-tomcat/2.1.7.RELEASE
And you'll find you need to set
tomcat.version to
9.0.22
By defining tomcat.version as 8.x, you are breaking it.
Another way to put it
You have to go ~way~ back to springboot 1.5.2.RELEASE or 1.5.3.RELEASE
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-tomcat/1.5.2.RELEASE
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-tomcat/1.5.3.RELEASE
(Again, in the two above links, looked at the COMPILE dependencies)
To find a version of tomcat (that is auto included with springboot) that gets close to tomcat 8.5.x (where 8.5.x is the one you are attempting to use)
That's pretty old.
The principal you are missing is that springboot auto includes dependencies. And anything else you import has to play nice with everything springboot auto includes.
And your current value for tomcat.version is NOT playing nice with everything springboot 2.1.7.RELEASE is auto including.
And now that you've been through all of that. You'll find you'll make your life easier if you engage the springboot world more completely.
Alot of times, springboot will have a (sub)package that will bring in the thing you really desire.
spring-boot-starter-jdbc
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc/2.1.7.RELEASE
You would probably be better off bringing that package in, vs hand-picking ones. Aka, get rid of your "tomcat-jdbc" include and see if the spring-boot-starter-jdbc can give you what you want.
The curse/blessing of spring-boot is that it is its own universe. But if you engage, you probably want to play by its rules more often than not.
PS
It is pom.xml, not porm.xml
Try adding spring-boot-starter-tomcat as a dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
Remove tomcat-juli and tomcat-jdbc dependencies. If you need JDBC support, add the corresponding starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
If you use JSP views, you will probably need the following dependencies as well:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
Also, pay attention to your dependencies versions. Spring Boot's parent POM defines version management for many common artifacts so you don't need to set the <version></version> for these libraries. See https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/htmlsingle/#appendix-dependency-versions

How should dependencies between modules be declared in a maven multi-module project?

Assume I have a maven multi-module project consisting of parent P and its modules A and B. How should a dependency of B to A be declared?
Until today I always used the following in B:
<dependency>
<groupId>org.example</groupId>
<artifactId>A</artifactId>
<version>${project.version}</version>
</dependency>
But a colleague just mentioned that it is also possible to create a dependency management entry for A in parent P
<depednencyManagement>
<dependency>
<groupId>org.example</groupId>
<artifactId>A</artifactId>
<version>${project.version}</version>
</dependency>
</dependencyManagement>
and then B only needs to specify:
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>A</artifactId>
</dependency>
</dependencies>
Is there any downside to either of those methods? Does maven intend one to be actually used? Or is there actually another style I'm missing?
In the project I'm working all modules have the same version and we are having much more than 3 modules and also some deeper nesting than only 2 levels. Does this have an influence on which declaration style should be preferred?

Using dependencies of an artifact

I have a complex Spring project with tens of dependencies and modules. I notice that some of them might be replaced by spring-boot-starters.
However, when I'm replacing some dependencies with starters in main, parent pom, I'm getting errors in children modules.
Here's an example:
PARENT POM
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
<version>2.0.5.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
MODULE POM
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
According to maven repository spring-boot-starter-activemq depends on, among others, spring-boot-starter and spring-jms.
Should these dependencies be available for modules?
Is there a way to use dependencies like that? I would make pom files shorter.
Or maybe is it a bad idea to do it like that and I should define all dependencies I will use in dependencyManagement?
In a POM, you should have all the dependencies that you directly use in your code. Do not rely on transitive resolution for things you actively use.
Your construction does not work because you did not manage the spring-jsm and spring-boot-starter in your dependencyManagement. Being a dependency of the managed dependency does not help.

Maven issue when overriding an environment specific systemPath property

I experienced issues with a maven build that does not behave the same way if done on Windows (like they were done in the past) or Linux (like I want to do them now).
I want to build a project that has a dependency on another project that pom that itself imports a pom that contains a Windows path.
my project | other project
|
mybuild -------|------> pom --------> pom with systemPath
dependency import
|
But in a nutshell, here is my pom:
<groupId>test.properties</groupId>
<artifactId>buildme</artifactId>
<version>1.0-SNAPSHOT</version>
...
<dependencies>
<dependency>
<groupId>test.properties.installme</groupId>
<artifactId>module</artifactId>
<version>1.0-SNAPSHOT</version>
<type>pom</type>
</dependency>
</dependencies>
And I depend on a pom that looks like this (not under my control)
<groupId>test.properties.installme</groupId>
<artifactId>module</artifactId>
<version>1.0-SNAPSHOT</version>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>test.properties.installme</groupId>
<artifactId>dependency</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>import</scope>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
</dependencies>
and the problem lies in this last pom (not under my control):
<modelVersion>4.0.0</modelVersion>
<groupId>test.properties.installme</groupId>
<artifactId>dependency</artifactId>
<version>1.0-SNAPSHOT</version>
...
<properties>
<com.sun.tools.path>D:/java/jdk1.8.0_65/lib/tools.jar</com.sun.tools.path>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.sun</groupId>
<artifactId>tools</artifactId>
<version>1.8</version>
<scope>system</scope>
<systemPath>${com.sun.tools.path}</systemPath>
</dependency>
</dependencies>
</dependencyManagement>
I have no control on the other project in question. I totally agree that a refactoring to use environment variable in place of the hard coded paths would solve my problem.
But instead the Windows path is defined in a property. One would think that overriding the value of the property depending on my platform would be enough. But it is not.
Unfortunately in this precise case case maven seems to behave to behave poorly.
Before applying any property override in any form (in settings.xml, -Dproperty=, redefinition in root pom), maven starts building the effective pom. And during that step, if it finds the pattern I mentioned above (a dependency on another pom that itself imports a pom that contains a Windows path), then it says:
The POM for <groupId>:<artifactId>:jar:<version> is invalid, transitive dependencies (if any) will not be available
As a consequence, my project needs to explicitly define all the dependencies of the second project. And I cannot rely on transitive dependencies which gives me a lot of trouble.
In order to illustrate the issue, I created a minimal example showing the problem. It can be found here:
https://github.com/fabricepipart/test-properties
Do you see any workaround for this?
Any way to override the value of the property and still benefit from the maven transitive dependencies?
Thanks a lot

pom.xml tomEE 1.6.0

I would like to find/create a pom.xml containing all libraries included in tomEE, using "provided" scope. Goal of this is to make it as "pom parent" of a webproject, and have no risk to use other library version, or other implementation.
Does a such pom.xml exist? or is there a simple way to create it?
thanks in advance
Clément
Because JavaEE is a specification, there are several available.
I use this one for several reasons. This is in my organization's parent pom so all the projects automatically pull it in:
<dependencies>
<dependency>
<groupId>org.apache.openejb</groupId>
<artifactId>javaee-api</artifactId>
<version>6.0-2</version>
<scope>provided</scope>
</dependency>
</dependencies>
Thanks to exabrial, the maven dependency i was looking for is this one :
<dependency>
<groupId>org.apache.openejb</groupId>
<artifactId>tomee-webapp</artifactId>
<version>1.6.0</version>
</dependency>

Resources