How to deploy a maven parent module with flat module hierarchy? - java

I have 3 maven modules. One is the parent grouping the other 2 modules.
All project folders are on the same root level.
Though the deployment is not working. What's wrong with the following configuration?
project-parent/pom.xml
project-commons/pom.xml
project-web/pom.xml
parent-pom:
<project>
<groupId>de.myproject</groupId>
<artifactId>project-parent</artifactId>
<packaging>pom</packaging>
<modules>
<!-- <module>../project-commons</module> -->
<module>../project-web</module>
</modules>
</project>
web-pom:
<parent>
<groupId>de.myproject</groupId>
<artifactId>project-parent</artifactId>
<version>1.0.0</version>
<relativePath>../project-parent/pom.xml</relativePath>
</parent>
Result:
[ERROR] The project de.myproject:project-parent:1.0.0 has 1 error
[ERROR] Child module \project-parent\..\project-web\pom.xml of \project-parent\pom.xml does not exist
The project structure:
svn/project-commons/trunk/pom.xml
svn/project-web/trunk/pom.xml
svn/project-parent/pom.xml

I will outline an approach that I have used successfully on large and small projects that may meet your needs.
pom.xml
superpom/pom.xml
utils0/pom.xml
utils1/pom.xml
utils2/pom.xml
services0/pom.xml
services1/pom.xml
services2/pom.xml
war0/pom.xml
war1/pom.xml
In this example, the utils and services modules produce jars; the war modules produce wars. There would be various dependencies between the utils, services and wars.
The superpom modules is of type pom and just contains the parent pom. Each of the util/service/war pom.xml refer to the parent with the relative path of ../superpom:
<parent>
<groupId>mygroup</groupId>
<artifactId>superpom</artifactId>
<version>1.3.3.3-SNAPSHOT</version>
<relativePath>../superpom</relativePath>
</parent>
The superpom/pom.xml does NOT contain any elements and does not refer to the "child" modules/poms in any way. The superpom contains shared properties, plugin configs, dependency versions, etc. It is a big pom. All the other module's poms are (generally) small.
The top-level pom contains the references to all the other modules (including superpom). It does not have a parent pom (at least not one that lives within this project hierarchy). You use the top-level (not superpom) to build everything. You can use profiles (or other means) to control which modules you want to build, but I have generally just built the whole tree from here. Support for SCM, CI builds, etc. lives in this top-level pom, which keeps all your other projects (including the parent pom) clean and concerned only with building and testing the artifacts.
I don't have any concept of "trunk" in my maven structure - that is an orthogonal concept. If I want to work on trunk or a branch, I check out the appropriate one and always have the same maven structure.

Related

Parent POM dependency tree discovery for sub modules (Maven)

I have created a maven goal that outputs a dependency tree for a given maven project to a YAML file. Using the m2eclipse plugin for Eclipse Photon.
Currently when I run the goal against a parent project (using type pom when setting up dependency), the only dependency returned is on the pom for the specific parent. Is there any way to prevent me needing to run this goal against all of the projects underneath the parent?
Might need a little more information on this, but are your children poms of the parent specified as modules within the parent pom?
Example:
<parentPom>
<modules>
<module>/path/to/childA</module>
</modules>
</parentPom>

Maven Modules with Variable as Version number

I got a Maven project with the following structure:
Module A (parent), Submodule B and Submodule C
In the parent pom.xml I am using a variable for settings the version of all projects:
...
<version>${revision}</version>
...
<properties>
<revision>1.1</revision>
</properties>
...
<modules>
<module>moduleB</module>
<module>moduleC</module>
</modules>
</project>
Module C is my distribution package which uses the shade plugin for packaging everything into one single jar.
In the submodules I set the parent like this:
<parent>
<groupId>group</groupId>
<artifactId>moduleA</artifactId>
<version>${revision}</version>
</parent>
Now I want to use Module C in another project, however I only get the following error when doing so:
Failed to execute goal on project newProject: Could not resolve dependencies for project group:newProject:jar:0.0.1-SNAPSHOT: Failed to collect dependencies at group:moduleC:jar:1.1: Failed to read artifact descriptor for group:moduleC:jar:1.1: Could not find artifact group:parent:pom:${revision} in nexus (NEXUS_URL)
I assume the problem is, that the variable value is not filled in when referencing Module C as dependency. How can I solve this issue? I already tried to clean the project before building and forcing to update all artifacts without success.
Maven expects all modules to have a hard version.
To avoid editing lots of poms, use the versions plugin, example:
mvn versions:set -DnewVersion=1.0.1
If you run the above command on the parent it will fix all the child poms.
See here for documentation.
Thanks to the comment of hadu.mansouri I could fix it. I used flatten-maven-plugin for flattening the pom.xml files. However, it seems to have a problem with the shade plugin, as the shaded module was the only module where it did not work. Thus, in the released shade module pom it said:
<version>${revision}</version>
for referencing the parent. I used the approach of the article linked in the comment. There, this extension was used: https://github.com/jcgay/unique-revision-maven-filtering
Using this instead of the flatten-maven-plugin, Maven builds the multi module project correctly with the single version property, and I can also use the shaded module in other projects properly.

How to remove dependency: maven sub-modules creates implicit dependency on parent module

I have a maven project
Parent Project (with the following modules) (package type pom)
API Project (package type jar)
Packaging Project (has a dependency on API Project) (package type custom)
I want to be able to deploy the API project to Nexus repositories so others can leverage that code. The Packaging Project is more of a supporting utility project for a smaller set of deployment use-cases. The Parent Project wraps it all together for me.
When I deploy the API project to the nexus repo, it deploys fine. If i try to make a brand new project that has a depdency on API, it finds the API dependency in nexus but then also wants the Parent project as well. Is there any way to get around publishing the parent project as its really isnt necessary for use of the API lib when used via the nexus repo?
Any tips on how to organize my maven proj to support this?
When you add a <parent> reference to a Maven project what you are doing is saying: "Take all the configuration from that parent and inject it into my model, then override with the following"
Therefore, in order for Maven to build the model of your project, it is necessary for Maven to retrieve the parent itself. In other words, adding a <parent> tag creates an explicit hard dependency between the parent and the child.
The good news is that Inheritance does not have to follow Aggregation. What does that exactly mean?
Aggregation is when you list <modules> in your pom. It tells Maven that the reactor (i.e. the set of projects that Maven builds) should also include the following (sub)projects.
Inheritance is when you set a project's <parent>.
Nowhere does Maven enforce that a project's <parent> has to list its children as <modules> and nowhere does Maven enforce that a projects <modules> must list the project as a <parent>.
Some people will set up their project like so
ROOT/
+- pom.xml
+- parent/
| \- pom.xml
+- api/
| \- pom.xml
\- packaging/
\- pom.xml
where the parent of ROOT, api and packaging is actually a child of ROOT. Or sometimes ROOT will be a standalone project with no parent [In fact this is a pattern I use a lot myself. When I am working on several related project I will throw together an aggregating pom.xml on my local disk and open that with my IDE and that way all the related code is available as one single "project", even though the actual modules may come from different sources]
So in your case the solution would be to remove the <parent> tag from your "API" module.
Now! There is a downside. When you remove the <parent> tag from your "API" module you have removed all the defaults that your parent project is providing, so you will need to copy those defaults that are relevant to the "API" project or else you may find subtle changes in behaviour. For example, you should definately copy over the pinning of plugin versions, and any <dependencyManagement> that is relevant to the "API" dependencies. There are other bits you may have to copy, but you should use the Maven command mvn help:effective-pom before and after removing the <parent> tag as an aid to seeing the effective differences
for my developments I use uber-pom maven plugin which merges information in maven project hierarchy and provides independent pom as result and I publish artifacts in maven central without any extra links to parents

How to restructure Maven multi-module project?

I appologize for the length of this post, but I had trouble making it more concise without presenting the picture. I've recently inherited the job of build-master for a maven 3.0 multi-module project. The problem is that the structure of the project/modules is a disaster. From the way things are currently stored in Source Control (we use RTC) to the pom structure of the modules, I'm tearing my hair out trying to get a full build cycle completed each time.
As a project hierarchy goes, all the modules are stored "flat"; ie: everything is at the same level. I have a parent pom, and all modules depend on the parent. However, the parent is at the same level as all my other modules.
Ex:
c:\dev\MyEarProject
+ parent-pom
- pom.xml
+ module1
- pom.xml (depends on parent-pom)
- src
- main
- ...
+ module2
- pom.xml (depends on parent-pom)
- src
- main
- ...
+ module3
- pom.xml (depends on parent-pom)
- src
- main
- ...
The parent pom defines all the modules required to build the project, as well as a bunch of properties for artifact version numbers used throughout the different submodules:
<modules>
<module>../module1</module>
<module>../module2</module>
<module>../module3</module>
</modules>
<properties>
<org.springframework.version>3.0.5.RELEASE</org.springframework.version>
<slf4j.version>1.6.4</slf4j.version>
<repositoryAddress>${snapshots.repo.url}</repositoryAddress>
<my.hibernate-module.dao.impl>1.2.3</my.hibernate-module.dao.impl>
<my.hibernate-module.dao.api>1.2.3</my.hibernate-module.dao.api>
</properties>
Each module's pom, in turn, depends on the parent pom via the pom's artifact number:
<parent>
<groupId>com.cws.cs.lendingsimulationservice</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0.6</version>
</parent>
To make things even more confusing, the actual artifact name may, or may not (depending on the module), match the module path. For example, module1 may be located in path c:\dev\MyEarProject\module1 but have artifact name hibernate-module. However, due to the way it is stored in RTC, the directory is called module1 when it is checked-out.
The easiest way to build everything, of course, is to go into c:\dev\MyEarProject\parent-pom\ and run mvn clean deploy. This works fine when in SNAPSHOT mode as the SNAPSHOT repo allows for multiple deployments of the same artifact version. But in release mode, this fails.
This structure is causing 2 problems for me.
Everytime I need to make a version change to a property in the parent, I have to update the parent-pom version number, and all the child modules parent pom's version, and all the child modules version themselves (since the parent changed).
Whenever I need to deploy a release cycle, mvn will throw an error if one of the modules has not changed since the last cycle and consequently cannot be redeployed to the same repo (the repo does not allow overwriting existing artifacts)
So I'm looking for the best way to restructure this project to avoid these problems. For the parent pom, I know I can use a relative path to point to the parent instead. However, given the "flat" structure of the modules, is this a recommended approach (ie: the parent pom relative path would be ../parent-pom/pom.xml - seems a little odd to me)? Additionally, given that the versioning control of the parent is independent of the modules, would using a relative path not just open the door to additional confusion (ie: there would be no way to know which version of the parent pom is associated with which version of the submodule).
Secondly, how can I build the entire ear without encountering the deploy errors I am having? Since the artifact already exists in the repo, I don't need to rebuild and redeploy it. I tried using --projects but with the number of modules involved, it gets extremely difficult to manage.
The first thing I really recommend is to restructure the projects folders ...which means to have the projects folder represent the structure which means NOT flatten the structure.
+-- parent-pom (pom.xml)
+--- module1 (pom.xml)
+--- module2 (pom.xml)
+--- module3 (pom.xml)
As a result of that the modules section your parent will be simplified like this:
<modules>
<module>module1</module>
<module>module2</module>
<module>module3</module>
</modules>
Furthermore the parent entries in your modules can be simplified as well like this:
<parent>
<groupId>com.cws.cs.lendingsimulationservice</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0.6</version>
</parent>
...which brings me to the next point:
If all your current project define their parent as above this is simply wrong, cause will try to find the parent within the repository and not in a upper level folder. In other words this is causing of much of your problems with releasing etc.
If we would fix this problem it has to look like this which I can't recommend:
<parent>
<groupId>com.cws.cs.lendingsimulationservice</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0.6</version>
<relativePath>../parent-pom/pom.xml</relativePath>
</parent>
An other thing which I observe is that you don't use SNAPTSHOT's which will be replaced by the release plugin during the release phase. And in relationship to that it will automatically change all versions in the appropriate parents etc.
In ideal case your modules should look like this:
<parent>
<groupId>com.cws.cs.lendingsimulationservice</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0.6</version>
</parent>
<artifactId>module-1</artifactId>
<!-- No Version or groupId -->
Cause all modules will inherit the version and groupId from their parent. Sometimes it's useful or needed to change a modules groupId but it's an exception.
On thing I reread is about the separate versioning of the parent. This simply does not make sense, cause it's the parent of their modules so put it into the same structure and of course the same VCS.
If you want to make some configuration/plugins versions, dependencies which should be used for other projects as well than make a separate corporate pom.xml which is a separate project and will be separately released etc.
After you finished your structure changes you can simply go into the parent-pom directory and do mvn clean package or mvn release:prepare release:perform from that folder and everything will simpler.
If you're publishing your POM, you'll have to release any updates but you don't need to modify POM versions by hand - you can update versions automatically using the versions plugin or the release plugin. I tend to prefer the release plugin as it'll commit to SCM for you too.
mvn versions:set
http://mojo.codehaus.org/versions-maven-plugin/
mvn release:prepare release:perform
http://maven.apache.org/plugins/maven-release-plugin/
Your repository manager may also allow overwriting an existing version but it's better practice to just release a new version.
I tend to prefer the flat module structure as it allows use of the parent folder to store common files e.g. checkstyle configuration. I also find it useful to share the group id across modules then name the module directory the same as the artifactId.
You are presenting contradicting requirements. You want to restructure your project but can't move things around. You want to simplify your deployment and release cycles but do not want to use a single version.
Given that changes in one module will inevitably affect all of the dependent modules, I would use a simple version'ing scheme where all the sub-modules inherit their parent's version. maven release:prepare and release cycles become simple. Use a release notes to track your changes and justify skipping unnecessary testing of unchanged modules (changes to a version do not change the build/binary output of the build process so you can use that as your primary argument).
Good luck with your project.

Having a maven project build its own dependencies?

With maven is it possible to have a top-level project who's packaging type is "war" which will build itself and all of its dependent modules (packaged as jar) and have the build generate a project.war file?
Much of the documentation examples and other examples I've seen often use a top-level project with packaging type of "pom" and the project only serves the purpose of tying the modules together. Can I avoid this?
So basically I need something which is effectively like declaring a <module>my-module</module> for maven to build, and in that same POM, declaring a <dependency>...my-module's artifact...</dependency> on that same module which needs to be built. Maybe a plugin as someone already suggested?
Update: In other words (to simplify the problem): If I have project A and project B, where project A depends on project B - is there a way for me to execute a build on project A and also have it automatically build project B (and include project B as its dependency - creating projectA.war which contains projectB.jar)?
super_aardvark suggested correct way but,
For requirement I would suggest following structure It is suitable and good structure also :
Consedering ProjectA as project-webapp , ProjectB as project-core
You can have following structure :
Your Grand Project :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.project</groupId>
<artifactId>project</artifactId>
<version>2.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Project Repository System</name>
<description>Project Repository System R2</description>
<modules>
<module>project-core</module>
<module>project-webapp</module>
</modules>
</project>
Your WebApp Project:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>com.mycompany.project</groupId>
<artifactId>project</artifactId>
<version>2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>project-webapp</artifactId>
<version>2.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>Project Web Application</name>
<description>Project Repository</description>
<dependency>
<groupId>com.mycompany.project</groupId>
<artifactId>project-core</artifactId>
<version>2.0-SNAPSHOT</version>
</dependency>
</project>
Your Core Project:
<project>
<parent>
<groupId>com.mycompany.project</groupId>
<artifactId>project</artifactId>
<version>2.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>project-core</artifactId>
<version>2.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Project Core</name>
<description>ProjectCore</description>
</project>
Your Directory structure should look like:
-------Grand Parent.pom
|
|--------project-webapp
| |
| project-webapp.pom
|
| -------project-core.pom
|
project-core.pom
From parent pom execute mvn clean install it will build both the web-app and core project
That's not really what a top-level project is for. Your WAR project has dependencies, which are the artifacts (e.g. jars) that will be included in the WAR (in WEB-INF/lib) when you run 'mvn package'. Your WAR project pom can have the top-level project as its parent, but it shouldn't be the parent of its dependencies. You may want to have that top-level project be the parent of both the WAR project and of the JAR projects that are dependencies in the WAR.
This is not possible in Maven 1, 2 or 3.
I'd recommend to give up this idea, because Maven's whole purpose is to enforce standardized development process. Don't fight the structure, just create a parent POM module and make the WAR module and other dependencies underneath it.
When you have a multi-module project and you're doing work in several modules simultaneously it can be tedious and error-prone to make sure all the necessary dependencies are updated.
In my situation, I would like my build system to detect changes and only build the modules that are necessary. One way this might be possible with maven is for someone to write a custom plugin that does this, which doesn't seem insurmountable given there are already complex plugins available, like the maven release plugin.
Others have already mentioned the aggregation pom concept, which is repeatable and does produce the necessary artifacts. But sometimes you end up building more than you really need to.
Maven profiles can help and here's a good article in that regard:
Using Aggregate and Parent POMs
Also note in the article the concept of the batch pom, which I was not previously aware of.
Remember, mvn clean install will push your artifact into your local repo. So if module A depends on module B, as long as your local repo has the latest build of module B then you should be all set. So, if there were an external tool that was watching for changes to module B and automatically built it when there were and pushed those changes into the local repo then when module A was rebuilt it would pick up those changes. There are continuous integration (CI) tools that can do this, like Jenkins. But you would need a local install to have this work directly with your local repo. It's still an option, though.
Another option would be for the CI environment to push your builds to an external maven repo (or even one you setup locally with something like Nexus). Then you setup your CI builds to pull from that location as well.
So, there are solutions that rely on other tools or potential plugins to do what you want - just depends how much time and effort you want to invest to get it all setup. But, once you get over that hurdle you'll have a system (and knowledge and experience) that you can use on all your projects, not to mention you'll be familiar with how many development shops/teams work.
I would recommend researching continuous integration and continuous delivery for more information and ideas.
In parent pom, you have to define a sequential order of modules to be compiled. You can add a war packing module to the last in that list. It will simply aggregate all previous compiled code together.
Not really - (Well, I can think of a couple of ways, but I'd not use them as they're convoluted and go against the basic ethos/practices of Maven).
Don't forget that the other purpose of the top-level pom is to provide a single point to set common details such the particular versions of dependencies used in the modules of the project.
NetBeans has an option that allows you to do exactly this with Maven projects but I don't know any pure Maven solutions. I think that the task is more suited for an IDE, because it knows for what depended projects you have the code (based of what projects you have opened in the workspace). How would Maven itself differentiate between a dependency that you want to build and one that needs to be fetched from the repository. And for those that need to be built, where should it look for the source code?
Anyway, another solution to the problem, that I used successfully a few times, is to create a simple shell script that navigates to your projects folders and starts the build then it waits for it to finish then proceeds to the next project and so on.

Categories