After i've been through some stackoverflow questions and documents about maven pom.xml relations i am still confused.
I have a project with its own pom.xml
-src/MyProject
-src/MyProject/POM.XML
Now i need to include another 3rd Party project
-src/MyProject
-src/MyProject/POM.XML
-src/OtherProject
-src/OtherProject/POM.XML
I need now to tell Maven when its building the MyProject POM.XML the other POM.XML has to be processed and included.
Reason: I need not only the jar built from OtherProject as a dependency, but what is more important: i need all the dependencies (jars) from the OtherProject as well for MyProject (and i dont want to enter every jar as a dependency manually for MyProject which are already correctly defined in the OtherProjects POM.XML).
What are possible solutions to do this?
You can make a multi-module maven application that consist of several projects (called "modules"). The multi-module application nests all the projects and the so-called master pom.xml, in which the application modules are defined. Each module will have to hold its own pom.xml, also.
So, your directory structure would like:
/application
|---/project1
|---/project2
|---pom.xml
The master pom.xml will define the application modules:
<project ...>
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>project1</module>
<module>project2</module>
</modules>
<dependencyManagement> ... </dependencyManagement>
...
</project>
Defined like this, project1 will build before project2.
Related
I am starting a new project as well as starting with Maven.
I am not sure my project-structure with Maven is decent and so I would like to ask. I describe the project with a little example.
The projects name should be MyPrj.
It consists of 3 parts (server, client, lib).
Server and client are programs (main) and lib does include helper-classes both will use (e.g. for logging).
I designed 3 maven-projects - 1 per part.
MyPrj/
client/
pom.xml, src, target, ...
server/
pom.xml, src, target, ...
lib/
pom.xml, src, target
The parts java package-names are
MyPrj.client
MyPrj.server
MyPrj.lib
The maven addressing is
groupId: MyPrj, artifactId: client, version: 0.1
groupId: MyPrj, artifactId: server, version: 0.1
groupId: MyPrj, artifactId: lib, version: 0.1
In them POM of client and server is a dependency to lib.
<dependency>
<groupId>MyPrj</groupId>
<artifactId>lib</artifactId>
<version>0.1</version>
</dependency>
Is that setup ok or not typical for a maven project?
Your Maven project looks good but you missed one thing : the parent.
Your MyPrj project should have its own pom.xml.
MyPrj/
pom.xml
client/
pom.xml, src, target, ...
server/
pom.xml, src, target, ...
lib/
pom.xml, src, target
In the pom.xml of MyPrj, you can declare the submodules of your Maven project as following :
<project>
...
<modules>
<module>client</module>
<module>server</module>
<module>lib</module>
</modules>
</project>
The parent of multi-module Maven project has a lot of interesting features (dependencies management, repositories, SCM management, ...).
I suggest you to take a look to the following documentation :
Guide to Working with Multiple Modules
I have a compilation error in one of my projects
Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
because it does not find all the classes from another project that I already included using
<dependency>
<groupId>com.laberint</groupId>
<artifactId>laberint-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
and I don't have any compilation problems from Eclipse. I already deleted all the repository.
The errors are because a missing classes that all are in the laberint-core artifact. I already deleted the whole repository folder
I also installed the jar
mvn install:install-file -Dfile=laberint-core-0.0.1-SNAPSHOT.jar -DgroupId=com.laberint -DartifactId=laberint-core -Dversion=0.0.1-SNAPSHOT -Dpackaging=jar
Simply create a jar from your another project and add it in local lib directory of your current project. Another option is install the jar file in to your local maven repository like below:-
mvn install:yourlocal-jarfile
-Dfile=<path-to-your jar>
-DgroupId=<group-id> --> the group that the file should be registered under
-DartifactId=<artifact-id> --> give a artifact name to your jar
-Dversion=<version> --> version of your jar file
-Dpackaging=<packaging> --> jar
-DgeneratePom=true
Also you can try with below option:-
<dependency>
<groupId>com.laberint</groupId>
<artifactId>laberint-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<systemPath>/pathto/yourJar.jar</systemPath>
</dependency>
Hope this will help your. Good Luck!!!
As you stated in your comment you are developing the laberint-core project in the same Eclipse workspace as the project you are trying to build. The problem you have is that while Eclipse knows each project in your workspace and can resolve those project dependencies, Maven does not have this Information which means that it searches the repositories (your local one in ~/.m2 and Maven Central) for the dependency.
As you said, you have already installed the laberint-core project to your local Maven repository via mvn install. That's why Maven can find the dependency at all and you do not get a dependency could not be resolved exception but I would guess that you installed the dependency some time ago and so some of the classes that your created in the Eclipse project after installing are missing.
There are two ways how you can resolve this issue
Create and install the dependency jar each time before you build the main project
This means some more manual overhead when you are building the main project but it can be automated if you are only building in Eclipse and not directly from the command line.
Create an aggregator project as shown here.
This would basically be a third project that consists only of a pom.xml file that looks somewhat like this:
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.laberint</groupId>
<artifactId>aggregator</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>relative/path/to/laberint-core</module>
<module>relative/path/to/laberint-main</module>
</modules>
</project>
To build the project you would then call the goals you called on the main project before on the aggregator project. Basically if you called mvn package before from the root directory of the main project you would now change to the root directory of the aggregator project and call mvn package. By convention the aggregator pom should lay in the parent directory of its modules.
I'd like to have a module in some kind of global project directory, so that I can include that module in all other projects that use that common code.
But how can I then tell a maven parent pom to include and compile this global shared module?
The following does not work:
svn/MyGlobalProject/project-commons/pom.xml //should be shared among different projects
svn/MyProject/web-parent/trunk/pom.xml //the parent pom used to build the application
svn/MyProject/web-parent/trunk/project-domain/pom.xml //submodule 1
svn/MyProject/web-parent/trunk/project-web/pom.xml //submodule 2
parent pom.xml:
<project>
<groupId>de.project</groupId>
<artifactId>project-parent</artifactId>
<packaging>pom</packaging>
<modules>
<module>project-domain</module>
<module>project-web</module>
<module>../project-commons</module> <!-- Error -->
</modules>
</project>
mvn package results in:
Child module trunk\project-commons of trunk\pom.xml does not exist
If you run mvn install on that global project, it will be installed in your local repository. Your other projects can then reference it as a dependency:
<dependency>
<groupId>whatever</groupId>
<artifactId>project-commons</artifactId>
<version>1.0</version>
</dependency>
The downside of this simplistic approach is that your other projects won't compile until you've checked-out project-commons and run mvn install.
A more advanced approach is to deploy a network-accessible repository (such as Artifactory or Nexus) which you can deploy global artifacts to. Artifactory has a community edition which is free. You can then list this repository in your settings file and Maven will resolve artifacts that are uploaded to it.
Using relative path to include some submodules is not a good practice...you will have a lot of problems.
Can not you just put the common project as a dependency of the parent module...
In this way you will have that "common project" in all the submodule that declare the parent project as a parent...
Why do you want to compile your "common" project every time you compile the parent pom?
Edited:
YOUR SVN:
svn/MyGlobalProject/project-commons/pom.xml //should be shared among different projects
svn/MyProject/web-parent/trunk/pom.xml //the parent pom used to build the application
svn/MyProject/web-parent/trunk/project-domain/pom.xml //submodule 1
svn/MyProject/web-parent/trunk/project-web/pom.xml //submodule 2
PARENT POM.XML:
<project>
<groupId>de.project</groupId>
<artifactId>project-parent</artifactId>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>de.project</groupId>
<artifactId>project-commons</artifactId>
<version>${common.project.version}</version>
<dependency>
<dependencies>
<modules>
<module>project-domain</module>
<module>project-web</module>
</modules>
Just like this...
in that way project-domain and project-web will inherit that dependency, and you will able to use it everywhere you want in submodules...
Than the use of dependency management could be a good improvements
I have a maven project which actually builds as multiple java projects. Project B contains a class which is a child of a class sin Project A. When I try to run this class in a debugger I get a NoSuchMethod error when the method tries to call any functionality from it's parent.
The Maven setup is designed to compile every single project and place it in the maven repository so other projects can find them (it has a sense of dependency so it builds pre-req projects firsts). This is all good for deployment, but I don't want to force people debugging in eclipse to do a maven install every time the start up their debugger. Instead I tried adding pre-req projects to the class path of the applicable projects (build path -> add class folder). This doesn't work. I think it's due to having both the maven repository and the class path in my build path? but the class folders should be parsed forced and the newer class folders should be parsed before the maven install right?
How can I configure this to work without needing to re-do a maven install each time?
What exactly do your pom files look like? I often use a setup where I have one parent Maven project that is comprised of other Maven sub projects.
I will have a parent pom that looks something like this:
<?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/xsd/maven-4.0.0.xsd">
<groupId>put group id here</groupId>
<artifactId>name of artifact id</artifactId>
<version>0.2.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>example-subproject-1</module>
<module>example-subproject-2</module>
</modules>
</project>
I'll then have pom files in the subprojects that look like this (assume this is the pom file for subproject 1):
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<parent>
<artifactId>artifact id of parent pom</artifactId>
<groupId>group id of parent pom</groupId>
<version>version number of parent pom</version>
</parent>
<groupId>group id</groupId>
<artifactId>artifact id</artifactId>
<packaging>packaging</packaging>
<version>1</version>
<name>put name here</name>
<dependencies>
<dependency>
<groupId>group id of example subproject 2</groupId>
<artifactId>example-subproject-2</artifactId>
<version>version number of example subproject 2</version>
</dependency>
</dependencies>
</project>
When I have things set up this way, I can compile the entire project if I'm in the root directory. If I just want to compile a specific directory, I just change into that directory. Make sure to include any needed subprojects in your dependencies section.
Make sure you have the m2eclipse plugin installed.
http://eclipse.org/m2e/download/
Also, install the m2eclipse-wtp plugin
http://marketplace.eclipse.org/content/maven-integration-eclipse-wtp#.UUdUhBxwrIU
Make sure you have created your projects as 'Maven' projects. So, if you look at your 'ProjectA->Properties->Builders', you should see a 'Maven Project Builder'.
If you follow all above steps, your project dependencies should resolve correctly and you should not have errors.
If you still have errors, pls post your eclipse project structure.
I have a pom file that looks similar to this
<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>myApp</groupId>
<artifactId>myAppId</artifactId>
<packaging>war</packaging>
<version>1.2-SNAPSHOT</version>
<name>Maven Test Webapp</name>
<url>http://maven.apache.org</url>
<dependency>
<groupId>com.manydesigns</groupId>
<artifactId>portofino-war</artifactId>
<version>3.1.10</version>
<type>war</type>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>TestName</finalName>
</build>
</project>
If i run 'mvn release:prepare' on the above pom file, the version of the artifact changes. i.e. it becomes
<version>1.2</version>
Now lets say i have gone and updated the portofino-war application which is a dependency of this pom file. portofino-war is now at version 3.1.11 but the parent pom file points to version 3.1.10 as shown above.
Is there any way i can update the parent pom (either via Maven or Jenkins) file if a new version of portofino-war is built?
Thanks
Edit
The application uses Maven overlays - http://maven.apache.org/plugins/maven-war-plugin/overlays.html to build a war file from other war files. This means that if any of the dependent modules are built, the parent module has to be built to produce the final war file.
The problem is that at the moment if i build any of the modules, i have to manually update the version in the parent pom file to build using the correct module version.
Edit 2
Thanks for your help Ralph. Basically this is what i would like to achieve:
What i am trying to do is create a maven project that will build a war file based on several modules. Assume the modules have the following structure:
Module 1
customerModule
|-webapp
|-jsp
|-customer
|-findCustomer.jsp
|-addNewCustomer.jsp
|-deleteCustomer.jsp
|-src
|-com
|-mycompany
|-customer
|-FindCustomerAction.java
|-AddCustomerAction.java
|-DeleteCustomer.java
Module2
productModule
|-webapp
|-jsp
|-product
|-productCustomer.jsp
|-addNewProduct.jsp
|-deleteProduct.jsp
|-src
|-com
|-mycompany
|-product
|-FindProductAction.java
|-AddProductAction.java
|-DeleteProduct.java
Module3
commonModule
|-webapp
|-css
|-style.css
|-jsp
|-templates
|-coreTemplate.jsp
|-src
com
|-mycomany
|-common
|-Logger.java
|-Access.java
|-META-INF
|-MANIFEST.MF
|-context.xml
|-WEB-INF
|-lib
|-oraclejdbc.lib
|-log4j.lib
|-common.lib
|-struts-config.xml
|-tiles-def.xml
|-web.xml
Each of the modules shown will be developed by a different team. Each team produces a war file and installs it in the local maven repository. As an example the repository could look like this
com
|-customerModule
|-customerModule.v2.1.war
|-customerModule.v3.0.war
|-productModule
|-productModule.v3.0.war
|-productModule.v3.1.war
|-commonModule
|-commonModule.v0.5.war
|-commonModule.v3.0.war
Now the build manager uses the above war files to build the final deployable war file. I was originally planning to use maven overlays to merge the three war files. I did test the merging of war files with overlays and found that the following configuration worked. i.e. using dependencies:
Note: These dependencies are in the commonModule pom file
<dependency>
<groupId>com</groupId>
<artifactId>customerModule</artifactId>
<version>3.0</version>
<type>war</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com</groupId>
<artifactId>productModule</artifactId>
<version>3.1</version>
<type>war</type>
<scope>compile</scope>
</dependency>
If i then build the commonModule module, i end up with one war file that contains all the contents of Module1, Module2 and Module3. Which ends up with something like this:
MyApp.war
|-webapp
|-css
|-style.css
|-jsp
|-customer
|-findCustomer.jsp
|-addNewCustomer.jsp
|-deleteCustomer.jsp
|-product
|-productCustomer.jsp
|-addNewProduct.jsp
|-deleteProduct.jsp
|-templates
|-coreTemplate.jsp
|-META-INF
|-MANIFEST.MF
|-context.xml
|-WEB-INF
|-lib
|-oraclejdbc.lib
|-log4j.lib
|-common.lib
|-customerModule.jar
|-productModule.jar
|-classes
|-com
|-mycomany
|-common
|-Logger.class
|-Access.class
|-struts-config.xml
|-tiles-def.xml
|-web.xml
The above works but requires a bit of manual intervention for a full release. Here is an example of what would happen if a module is modified
Team 1 updating module 1
- Team 1 makes changes to module 1 and check in changes into CVS
- Team 1 installs module 1 onto the maven repository by issuing mvn:prepare and mvn:perform on module 1. This adds a new version of customerModule.war on to the local repository
- Team 1 updates the dependency version for module 1 in the pom file used to merge the war files (i.e. commonModule)
- Team 1 builds the deployable war file by building the commonModule.
The above does not use a multi module project as you suggested so i am trying to understand how the versioning would work with multi module projects. For example, lets say the multi module project will look like this
MyApp
|- productModule
|-pom.xml
|- customerModule
|-pom.xml
|- commonModule
|-pom.xml
|-pom.xml
What is the difference in adding the version number in each child module compared to just havin the version number on the parent?
You say that the child modules will use the parent version. Lets say the parent version is currently version 3.4, how will it know that it is supposed to use version 3.1 of the productModule.war?
And finally, if team 1 has made a change to one of the child modules, would they still need to build it and deploy it on to the maven repository as an individual product first before building the multi-module project or can this be done as one step?
How would this work if i want to make a patch release that does not necessarily mean using the latest version of a specific module?
Thanks
For the scenario described in the "Edit" part of the question, I would recommend to put all war files in a single: multi module project.
You may want to use a dependency range instead of updating the pom: http://docs.codehaus.org/display/MAVEN/Dependency+Mediation+and+Conflict+Resolution#DependencyMediationandConflictResolution-DependencyVersionRanges