I am currently trying to migrate a multi-app project from Ant to Maven.
At the moment the project consists of multiple packages, creating some kind of dependency tree, without circular dependencies. The leaves of this tree are "application" packages, containing a Main. Intermediate nodes are "library" packages, used by other library "packages" or "application" packages.
The nodes are allowed to "grow together" to a single node or leaf.
I figured out, that those packages should probably be grouped into maven modules and I now have a structure similar to this:
root
- lib1
- lib1A (depends on lib1)
- lib1B (depends on lib1)
- app1A (depends on lib1A)
- lib2 (depends on lib1B)
- lib2A (depends on lib2)
- lib2B (depends on lib2)
- app2 (depends on lib2A and lib2B)
- lib3 (depends on lib2A and lib2B)
- app3A (depends on lib3)
- app3B (depends on lib3)
Basically a library and an application can depend on one or more other libraries.
Now I would like to be able to build each app on it's own and create an executable jar for it.
The way I am trying to do it now is the following:
configure the pom.xml of every app to use maven-assembly-plugin to create an executable jar.
Build each needed module for a specific app.
Build the app-module, which results in a executable jar.
So the build for app2 would build lib1, lib1A and lib1B, lib2, lib2A and lib2B and finally app2.
However, to automate the build, I would need to create a build-script for every app, which takes care of building all needed dependecies, which maven should already do by itself.
Also, if I want to build multiple apps at once, I would need to build all libraries multiple times, or track the already built modules by myself.
As I am new to maven, I am not sure if that's the correct way to manage such a multi-app project.
So I am asking for some advice on how to correctly manage this use case.
EDIT:
To clarify what I would like to be able to do:
build a single app with it's dependencies,
without building all apps (running maven on the parent pom).
build multiple apps (not all) with their dependencies, without building the dependencies multiple times.
If you define the dependencies in the respective POM and build the whole project (at the root level), then Maven automatically orders the modules topologically, which means that builds every module once and everything is done in the right order.
I am now using a parent project, which defines the maven version, the common dependencies and the common plugin configurations.
The parent project also defines it's child modules in module-tags.
Every child module references this parent project and uses the same version.
To build the applications, I am running maven inside the parent project, using the -pl and -am flag, as mentioned in this comment.
The -pl flag tells maven to only build the listed modules, instead of building the whole project.
The -am flag tells maven to also build the needed dependencies.
Example:
Given the following structure:
parent
---- lib1
---- lib1A (depends on lib1)
---- lib1B (depends on lib1)
---- lib2 (depends on lib1B)
---- lib2A (depends on lib2)
---- lib2B (depends on lib2)
---- app1A (depends on lib1A)
---- app2A (depends on lib2A)
---- app2B (depends on lib2B)
Executing mvn clean install -pl app1A,app2A -am would build all modules except app2B and lib2B.
Also, the module lib1, which is used by app1A and app2A would only be built once.
Usually, you want to version each module independently, but in our case this would introduce a huge effort, since we have a lot of modules building on top of each other. Small changes in the "lowest" module (lib1 in the example) would cause changes in almost every module.
So in this case we would need to increase every version number and update all referenced dependencies in all modules.
We instead decided to always rebuild all dependencies, resulting in a always up-to-date Jar. That's why we only manage the maven version in the parent project.
I think with maven multi-module, you just need to navigate to the module that you want to build, then run maven command from there. Maven will build that module with associated dependencies automatically without build unnecessary modules.
Edited: The original answer was incorrect, after did some test I found the following should be helpful:
Maven Modules + Building a Single Specific Module
You just need to add -pl and -am flags when building sepecific module from parent level.
Related
This question already has answers here:
How to activate a Maven profile per pom.xml?
(3 answers)
Closed 7 years ago.
I'm not familiar with Maven and am trying to figure out how it works on our existing project.
project and folder structure is basically
A
A\1
A\2
A\3
Inside each folder is a pom file. Each pom contains 1 or more defined profiles.
What I do not understand is with this command
A>mvn install
How do all of the pom get executed and which profiles are being executed?
I don't see any tags marked with activebydefault
Frustrated when I need to spend time learning at step 1 and build some projects but am forced to be at step 50 without anybody on the team that knows the first thing about Maven. Of course solutions are always due yesterday.
Profiles can be specified in your POM, in your parent POM, in your settings. Hence, looking just at your POM file may not be enough.
Running mvn help:active-profiles would give you a list of all active profiles and from which source (pom or settings).
Running mvn help:all-profiles would give you a list of all available profiles, the active ones and from which source (pom or settings).
Running mvn help:effective-pom -Doutput=full-pom.xml would provide you the full POM file (in the full-pom.xml generated file), as a merging of current pom, parent pom and settings. That would be the full source of true.
The structure you describe is for a multi-module maven project, which means A is the aggregator project (having packaging pom, its only delivery is a pom file, its only function is to provide the modules it will build).
However, beware that in Maven aggregation and inheritance are two different concepts, which are often used together: aggregation means I will build as part of my build all of my defined modules; inheritance means I will inherit configuration from my parent pom. As such, A\1 may inherit profiles from project A if in the pom of A\1 you will find A defined as parent (which is often the case, to have an aggregator which is also parent of all the defined modules).
Why to have an aggregator? To have a centralized build and location of correlated sub-projects while still keep a good separation of concerns across sub-modules. Moreover, as Maven best practices, a project should only generate one artefact, hence it might be the case to have a web application having logic in one module, war generation in another module, ear generation in yet another module, for instance.
Why to have inheritance? To have a centralized place where to set shared/common configuration, like profiles but also dependencies and dependencies management.
Lastly, it is a common misunderstanding and hence be also aware that:
If a profile is active by default in Maven, it will be part of the default build. However, if you activate a profile via command line (via the -P option) you will then activate the requested profile but also and automatically deactivate the one which was active by default
the mechanism above doesn't apply to profiles defined in the settings.xml of your maven installation (which are applied by default, if activated, to all the Maven builds on the concerned machine).
Update A further note on this answer leveraged by some comments: a Maven build is specified as part of the build section (a flow of plugins executions), which doesn't necessarily need profiles. Profiles are generally defined to add a further behavior to the build, but it is good practice to have a build building successfully regardless of any activable profile, that is, I don't have to know about the defined profiles to run your build, it's a core concept of maven, harmonization and convention over configuration: given a Maven project, I can always assume that simply mvn clean install would do the required magic.
For a list of common questions about starting with Maven, the official Getting Started Guide already provides a good help.
Also check the Profiles Pitfalls of the official Introduction to Profiles for further guidance on profiles.
No profile is active unless you have one marked as activeByDefault.
We have a very modular Maven pom set up, with common jars and specific jars all being bundled in to a war and ear. As there is so much reuse amongst the 70+ modules we do not use multi-module and each module can and does have its own lifecycle and can be released independently of any other module.
All modules inherit from various parent poms and ultimately every pom inherits from a master POM where all the external versions such as spring and the common local module versions are defined.
This works ok until we come to do a release. If the master POM requires a change, which it does occasionally, ALL poms need to be updated one way or another. I am aware that the maven versions plugin can update a specific POM with the latest SNAPSHOT versions etc, but this only works at the individual POM level.
We would like to be able to alter all poms once a release has been completed, iteratively.
We do not use multi-module POMs and are not able to change our build process to use this mechanism.
I have read around SO and the nearest to the problem is here.
https://stackoverflow.com/a/3615417/1279002
Writing a shell script seems to be one solution, but we have a Windows and Linux mix of development and build systems. I am sure other will have solved this issue. Can anybody advise how they have solved this?
In a similar setup, I have all my parent POMs always stay at 1.0.0-SNAPSHOT and setup various properties in the parent POMs to track internal module version numbers (so this setup now centralizes both dependency management versions AND custom module versions [via properties] into the parent POMs).
So if I need to update the reference to some com.myco:module-x, I can do this:
Edit the appropriate parent POM and set the <module-x.version>1.2.3</module-x.version> property to the new value
Rebuild/install the parent POM
Rebuild the target end-application (ear, war, jar app etc).
Where in module-x's POM it's definition may be something like this:
<groupId>com.myco</groupId>
<artifactId>module-x</artifactId>
<version>${module-x.version}</version>
And any POMs which reference com.myco:module-x refernece it via ${module-x.version} as well.
At this point, the build of the application will pickup the changes in the parent POM and thus any references it has to any properties defined in the parent POM.
There's some subtle nuances in doing this in terms of when/how the "middle man" modules need to get rebuilt...
But I really don't believe there is any silver bullet here.
The approach we've taken works pretty well, coupled with Jenkins to automate rebuilds of modules with interdependencies whenever parent POMs change.
The benefit here is that you seldom need to modify anything but the parent POMs, ever. The middle-man modules and application POMs don't need to be updated to get new version numbers, etc.
The biggest caveat though is that two rebuilds of a given module at the same version could result in a different artifact, for example:
module-x has a dependency on module-y:1.2.3
module-x is built (jar is created with a MANIFEST referencing module-y:1.2.3)
parent POM is modified to set <module-y.version>1.2.4</module-y.version>
module-y is rebuilt to create the 1.2.4 artifact
module-x is built (jar is created with a MANIFEST referencing module-y:1.2.4)
But note that #2 and #5 both built module-x with the same version for module-x, but with two different embedded MANIFEST's referencing different module-y versions.
We overcome this nuance by automating all the dependent modules with our Jenkins CI server
Let's say I have a maven project which has some maven modules inside.
My main module depends on the other modules, so when I compile the main module they should be compiled together.
The question is, how to add these modules as dependencies to the main module?
I know if I have a custom lib that I want to use with maven, let's say a utilities project, I have to compile the jar of the project, do a mvn install:install-file on it to install it on the local repository and then add it to the pom.xml.
Do I have to do this with all my modules and add the dependency to the pom.xml on my main module? Because if it should be done like this, there will be a lot of work to do when changing code on the other modules.
What is the best practice to use avoid the trouble of compiling/installing the modules to local repository?
The question is, how to add these modules as dependencies to the main module?
The same way you add any other dependency to your maven project. By adding group id, artifact id and version to <dependency> element
Do I have to do this with all my modules and add the dependency to the pom.xml on my main module?
If your main module depends on some module A then only the pom of the main module should contain dependency declaration towards module A. You do that for all the dependencies of your module.
I don't know what you mean by "a lot of work when changing the code on other modules". Maven has nothing to do with code changes, it just builds the projects whatever they look like at the given moment...
What is the best practice to use avoid the trouble of compiling/installing the modules to local repository?
Any project that you invoke mvn install on gets built and it's jar copied to local repository. That's all you need to do to get the jar into the repo. This will also put all the dependent jars, if available, into the local repo.
As for best practices for multi module projects:
If your parent project (the one that has modules inside) has <modules> section that lists the modules of your application, and modules are in subdirectories of your parent project, then you simply mvn install (or whatever you want to do) the parent project and that will cause all the modules to be built in order defined by declared dependencies between them. That means that if your main module has dependency on module A, then module A will be built before the main module. This way you can build and install all your modules with one command. On the other hand this approach makes more tight coupling between modules which is not desired in some cases, so it depends on your use case whether it is a good approach or not.
The problem is, in our company we have a project with multiple sub-modules, however one of the sub-modules is just a collection of API declarations and is meant for other (3rd praty) projects to use. I want to keep it as a sub-module because is easier to maintain and build (dependency and property inheritance). Other sub-modules in this project are also dependant on it.
The question I have is, if there exist a good practice or a nice way to execute a deploy phase that will upload just this sub-module to a different repository (can be duplicated too) without it having a dependency to parent pom.
What I have already tried:
I have already checked the deploy:deploy-file, but the problem is when it comes to SNAPSHOT builds. We wish to be able to publish SNAPSHOTS and release builds, and snapshots have different repository than release ones, but deploy-file goal can only have one url parameter. I do not wish to use different profile for snapshot deploy. Than I tried to use maven build-helper and its regex-property to be able to change the repository url if the version is a SNAPSHOT, but was unable to do so because of the plugin and regex limitations.
The last option is I can make a plugin for this, but I wish to know if there is a more elegant way to solve this the "maven way".
You can deploy this module separately but only for SNAPSHOT's for a release it does not make sense. The deployment of a module can be done via:
mvn -pl TheModuleYouWouldLikeToDeploy deploy
may be you need to add the option -am (also make dependencies) like:
mvn -am -pl TheModuleYouWouldLikeToDeploy deploy
Apart from that your approach sounds wrong cause if you are using a multi-module build why not deploying the whole build via mvn deploy ? May be it would be better to let do the job via a CI tool like Jenkins.
What's the best way to setup Maven for a project that has a SmartClient architecture? Consider the following packages:
myproject.core
myproject.server
myproject.client
Of course there are several sub-packages in each. Client and Server both use core. I see two main options:
Make an uber-POM in myproject to cover all three and have some sort of build parameter to identify what to build.
Make a POM in each package above (one for core, another for server and another for client).
Here are the outputs we need to build (at a minimum):
Standalone.jar: A test application that will launch the server and a client.
Server.war: A WAR file that can be deployed to Tomcat.
Client.jar: The SmartClient without any server code.
Is option #1 even possible? If so, is it good practice? From my initial research, option #2 sounds like best practice. However, jumping from POM to POM when all the code is intimately related sounds like extra work and extra clutter we may not need. Should I just stick with option #2?
Maven has a general rule that there should be only a single artifact per project. In other words, option #1 wouldn't allow you to produce a server.war, a client.jar, etc without fighting against maven. This would be a big mess and you wouldn't be able to take advantage of maven plugins. No, really, you don't want this. So just go for option #2, with a structure like (omitting the src directory):
.
|-- core
| `-- pom.xml
|-- server
| `-- pom.xml
|-- client
| `-- pom.xml
`-- pom.xml
Regarding your concern about jumping from POM to POM, well, just import all modules into your IDE and you won't really notice it. This just works pretty well for lots of people.
UPDATE (to cover questions from the OP in comments):
Fighting against Maven doesn't sound fun.
No, and you will loose :)
What is in the pom.xml at the root level?
This is a parent POM used for Project Aggregation. Quoting the Introduction to the POM document:
Project Aggregation is similar to
Project Inheritance. But instead of
specifying the parent POM from the
module, it specifies the modules from
the parent POM. By doing so, the
parent project now knows its modules,
and if a Maven command is invoked
against the parent project, that Maven
command will then be executed to the
parent's modules as well. To do
Project Aggregation, you must do the
following:
Change the parent POMs packaging to the value "pom" .
Specify in the parent POM the directories of its modules (children
POMs)
Project aggregation and project inheritance are often used together. Refer to the mentioned document for more details.
By "single artifact per project" do you mean that there should be a separate POM for Standalone.jar, Server.war, and Client.jar (three total POMs)?
Yes, this is what I mean, one project generates one artifact (there are some exceptions but this is true 99% of the time). This is a maven best practice that you should (must?) follow.
What if I also want a Server.jar, a simple server based with Grizzly included? Wouldn't server need two POM's?
I think that the maven way to handle this would be to use assemblies and there is no unique answer to your question (this might be one of the exception to the rule mentioned above). But this won't prevent you from starting.
Also, how would one kick off a build that would result in all three artifacts getting produced?
Launch your maven command from an aggregating project as we saw (aka "multi-modules build").