How to setup maven parent and child project as separate projects? - java

There is a project (type=pom), which is supposed to be used as a parent for another project.
parent
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>my-firm</groupId>
<artifactId>custom-parent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<distributionManagement>
<repository>
<id>lib-repo-local</id>
<name>my-releases</name>
<url>http://artifactory.local:8081/artifactory/libs-release-local</url>
</repository>
<snapshotRepository>
<id>lib-repo-snapshots</id>
<name>my-snapshots</name>
<url>http://artifactory.local:8081/artifactory/libs-snapshot-local</url>
</snapshotRepository>
</distributionManagement>
</project>
child
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>my-firm</groupId>
<artifactId>custom-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>child-sample</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<distributionManagement>
<repository>
<id>lib-repo-local</id>
<name>my-releases</name>
<url>http://artifactory.local:8081/artifactory/libs-release-local</url>
</repository>
<snapshotRepository>
<id>lib-repo-snapshots</id>
<name>my-snapshots</name>
<url>http://artifactory.local:8081/artifactory/libs-snapshot-local</url>
</snapshotRepository>
</distributionManagement>
</project>
The parent project is deployed to the remote repository - artifact my-firm:custom-parent:1.0.0 is available.
When I run mvn clean on the child project there's an error
[FATAL] Non-resolvable parent POM for my-firm:child-sample:0.0.1:
Failure to find my-firm:custom-parent:1.0.0 in https://repo.maven.apache.org/maven2
was cached in the local repository, resolution will not be reattempted until
the update interval of central has elapsed or updates are forced
and 'parent.relativePath' points at wrong local POM # line 7, column 11
All the three points in the error message seem to be unrelated to my intentions.
Maven does not try to look in the repo described in distributionManagement, but complaints about maven.central
Nothing is cached in local repository - all artifacts removed from there before the build.
The parent.relativePath is intentionally absent to have the child project agnostic to the parent project location and let it rely only on the deployed artifact (parent pom).
Please, show how to edit the poms to have child and parent as separate projects and let child to depend only on the parent artifact.

Please note that <distributionManagement> is only for upload. This is where Maven puts the artifacts if you run mvn deploy.
So if you want Maven to look into your artifactory for the parent POM, you need to add an appropriate <repository> element or -- which is the preferred way -- configure your artifactory in the settings.xml.
Nevertheless if you build the parent first on some machine and then build the child on the same machine, the parent POM is read from the local repository. It is not removed from there in any way. I don't know what went wrong in your case, but I guess you either had a different local repository for both builds or the content was somehow erased in between.

Related

Can the submodules use the reactor as parent in Maven?

Hello Stackoverflow community,
i recently started working with maven to see what is possible or better to see if its easier to have a dependency manager or including everything to your own.
Basic Informations
Repository
https://github.com/JXCoding/MavenTests
Reactor
<groupId>de.jxson.maven</groupId>
<artifactId>MavenTests</artifactId>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<modules>
<module>API</module>
<module>v1_18_R1</module>
</modules>
submodule API
<parent>
<artifactId>MavenTests</artifactId>
<groupId>de.jxson.maven</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>API</artifactId>
<dependencies>
...
</dependencies>
Which depends of reactor as parent
submodule v1_18_R1
<parent>
<artifactId>MavenTests</artifactId>
<groupId>de.jxson.maven</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<artifactId>v1_18_R1</artifactId>
<dependencies>
<dependency>
<groupId>de.jxson.maven</groupId>
<artifactId>API</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
Which depends of API and reactor as parent
My Problem is:
When I build with mvn clean package, there is an error on my module v1_18_R1 in which a class from API is not found.
Questions:
Why a class is not found if the required dependency is already added?
Usually maven reactor is used for:
Collects all the available modules to build
Sorts the projects into the correct build order
Builds the selected projects in order
And not to be as parent of another projects. If you need to centralize libraries , versions, etc create a extra project with <packaging>pom</packaging>.
Solution
Remove the parent from your submodules
Add this to all of your submodules which requires spigot jars
<repositories>
<repository>
<id>elmakers-repo</id>
<url>https://maven.elmakers.com/repository/</url>
</repository>
</repositories>
WIth these fixes, I was able to build your git repository with mvn clean package
Spigot notes
offical git repository don't build https://hub.spigotmc.org/stash/projects/SPIGOT
Official repository don't works: https://www.spigotmc.org/wiki/spigot-maven/
Only this repository works https://maven.elmakers.com/repository/org/spigotmc/spigot/

Find unresolved maven dependencies in multi-module maven project

I'd like maven to report unresolved dependencies in multi-module maven Java project which has below structure:
multi-module-java-app/
├── app1
│ ├── pom.xml
│ └── src
├── app2
│ ├── pom.xml
│ └── src
└── pom.xml
poms are at the bottom.
Background:
Maven is used as a dependency management and build tool. Artifactory is repository manager. Artifacts may be built using maven locally on a developer’s environment or on Jenkins build server. Artifactory periodically moves artifacts to special archive repository which is part of all repository virtual.
Maven caches locally built artifacts in~/.m2 directory on the computer where Maven runs whether it’s developer environment or build server.
Problem
Several issues may arise:
Local builds on developers’ VMs may succeed, but fail in Jenkins.
Local builds, Jenkins builds may succeed, but fail on another developer’s VM.
Cause
Present/missing artifacts on a developer .m2 cache, missing artifacts in build server’s .m2 cache and/or archive Artifactory repository
Proposed solution
Run [path_to_maven]mvn dependency:list. [path_to_maven] has custom maven installation (with empty .m2 cache) in the root folder of the project. Custom maven is also configured using settings.xml to use special non-archived repository (all repository without the archive).
The output is like below:
It reports unresolved dependencies as well as dependent artifacts which miss them.
However this solution has 2 main drawbacks:
.m2 missing slows down the detection significantly as all the dependencies have to be downloaded
unresolved artifacts or modules which miss them are always snapshots.
Running mvn -B -q versions:set -DnewVersion=[some_version] solves the second. This command runs during release pipeline anyway.
However it's not clear how to solve the first.
How to find unresolved maven dependencies while using .m2, so that unresolved dependencies may be detected quickly during Jenkins build after each push to feature branch?
The only idea that pops is that .m2 on build server will be synced with Artifactory.
.m2 on developers' machines can be synced as well using some sort of custom plugin that uses rsync. Is there a known plugin that does this?
The ultimate goal is to remove archive repository and let the builds fail. But, first developers need to align the dependencies to the latest versions.
root pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project 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">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>multi-module-java-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>multi-module-java-app</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<pluginRepositories>
<pluginRepository>
<id>plugins</id>
<name>plugins</name>
<url>http://localhost:8081/artifactory/all</url>
</pluginRepository>
</pluginRepositories>
<repositories>
<repository>
<id>all</id>
<name>all</name>
<url>http://localhost:8081/artifactory/all</url>
</repository>
</repositories>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>app1</module>
<module>app2</module>
</modules>
</project>
app 1 pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project 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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>multi-module-java-app</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.mycompany.app.app1</groupId>
<artifactId>app1</artifactId>
<version>1.0-SNAPSHOT</version>
<name>app1</name>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<finalName>${artifactId}</finalName>
</configuration>
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<id>plugins</id>
<name>plugins</name>
<url>http://localhost:8081/artifactory/all</url>
</pluginRepository>
</pluginRepositories>
<repositories>
<repository>
<id>all</id>
<name>all</name>
<url>http://localhost:8081/artifactory/all</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>spring-boot</artifactId>
<version>0.0.1-20200510.095344-1</version>
</dependency>
</dependencies>
</project>
app2 pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project 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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>multi-module-java-app</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>com.mycompany.app.app2</groupId>
<artifactId>app2</artifactId>
<version>1.0-SNAPSHOT</version>
<name>app2</name>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<finalName>${artifactId}</finalName>
</configuration>
</plugin>
</plugins>
</build>
<pluginRepositories>
<pluginRepository>
<id>plugins</id>
<name>plugins</name>
<url>http://localhost:8081/artifactory/all</url>
</pluginRepository>
</pluginRepositories>
<repositories>
<repository>
<id>all</id>
<name>all</name>
<url>http://localhost:8081/artifactory/all</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>spring-boot</artifactId>
<version>0.0.1-20200510.095344-1</version>
</dependency>
</dependencies>
</project>
I have run into this exact issue where the developer's local build environment was different from Jenkins Slave environment. In the ideal world, the developer needs to baseline their local environment with that of the slave, or depend entirely on Jenkins job builds once initial stages of development are complete.
I appreciate the fact that you are trying to provide an automated sync feature of the .m2 repositories, it is feasible but adds scope for error and additional routine maintenance tasks, not to mention user education issues. For instance, how will you ensure that the .m2 is the latest version? In terms of maven dependencies, the developer knows best, or they may be introducing new dependencies which do not exist on the slave yet. Thereby, I suggest fixing the root problem of developer not aligning their dependencies which is more design related than automation.
Not sure if you want to take this path, but may help someone:
Eliminate the need for .m2 repositories in local machines of developers. The m2 cache creates a problem, if the developer's machine gets wiped out or corrupt and there will be a need for updates, audits and reconciliation.
Eliminate the need for .m2 in Jenkins slaves. The problem here is, multiple slaves tend to have different .m2 cache content and syncing back and forth from Artifactory and then developers also syncing it to their local sounds complicated. There is no saying that all these .m2 will be in sync at any point of time and a builds may still get executed with an n-1 version of it.
Now that there is no .m2 , we still need a place for developers to pull dependencies from. Push all your dependencies to a repo in Artifactory and actively maintain it. Use the setting.xml feature to pull the standard dependencies. If a developer is building in his local machine, via Eclipse or other, the dependencies will be available to be pulled from the IDE itself by using the same xml reference so there is no local cache maintained on the developer's machine.
When the build environment has a minor difference between the local and the Jenkins Slave This causes the .jar to be the same size or slightly different in kilobytes of size.
To identify this difference between jar files use any tools listed here in this post, it also helps developers to identify which dependency is out of sync, by themselves:
Comparing two .jar files
If this design is implemented, the Artifactory repository containing the dependencies becomes the single source of truth for dependencies, you need to work with developers to create a cadence as to how the dependencies will be updated and consumed to/from this single source of truth. I hope this is useful.

Could not find parent artifact xxxxx:pom:2.0-SNAPSHOT

I have a parent project xxx-third, which has nothing but a pom declaring some dependencies and build configurations.
After I deploy it to the nexus and I can find it in the nexus web,I declare this xxx-thrid as my parent project of myProject.
Howerver, I still have the maven error complaining that Cound not find artifact com.myCom:xxx-third:pom:2.0-SNAPSHOT # com.myCom:myProject.
But if I do install locally with the code, the problem will resolve, this is annoying! Why and how to solve it?
It is because this artifact is in your local .m2 repository on your local machine, but can't be downloaded from remote respository by your build server.
The local repostiory is in path:
{USER_HOME}\.m2\repository\
You can copy the required dependency from your local repository to the local repository on your build server, then it will read the jar dependecy from local repo instead of fetching it from remote repo.
Your parent POM is not resolved. There are three options to solve this:
1) Add the parent POM to your local repository
2) Add a relativePath to your child POM pointing to your parent POM (only makes sense in a multi-module project where source is in the same repository)
<parent>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<relativePath>...</relativePath>
</parent>
3) Add a repository configuration to your settings.xml (e.g. makes sense if you have a company wide POM)
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<profiles>
<profile>
...
<repositories>
...
</repositories>
...
</profile>
</profiles>
...
As far as I understand 3) is your solution. See also:
https://maven.apache.org/guides/introduction/introduction-to-the-pom.html
https://maven.apache.org/settings.html

Why do I need to specify a repository in my settings.xml file

I've run into a strange Maven configuration issue that I have never encountered before, and am confused as to my solution.
I have a local Nexus server that I use as a mirror for everything. Until now, I've only had the following mirror in my settings.xml file:
<mirrors>
<mirror>
<id>nexus</id>
<mirrorOf>*</mirrorOf>
<name>WADA Nexus</name>
<url>https://nexus.domain.org/repository/Public/</url>
</mirror>
</mirrors>
However, I recently wanted to create my own custom parent pom that I have deployed to my Nexus repo. In my project, I have pointed to my parent pom:
<parent>
<groupId>org.domain</groupId>
<artifactId>root-pom</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
However when I now try to run my build, it fails with the following:
ERROR: Failed to parse POMs
org.apache.maven.project.ProjectBuildingException: Some problems were encountered while processing the POMs:
[FATAL] Non-resolvable parent POM: Could not find artifact org.domain:root-pom:pom:1.0.0-SNAPSHOT and 'parent.relativePath' points at wrong local POM # line 9, column 10
For some reason, maven is not trying to look up the parent pom in my Nexus repo.
My only workaround was to define a random repository value in my settings.xml file:
<repositories>
<repository>
<id>nexus</id>
<releases>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</snapshots>
<url>https://www.google.com/anythingCanGoHere</url>
<layout>default</layout>
</repository>
</repositories>
Since I've mirrored all Repos/URLs, I can set that url to any value and maven will now pick up my parent pom.
So, why do I even need to specify the repository at all? Shouldn't maven automatically try to resolve the parent pom against maven central or some other default repository?
It is not a strange configuration issue, but simply a misunderstanding from your side. What you have done is to populate <distributionManagement/> in your parent POM and added a catch-all mirror in your settings.xml with your local Nexus instance and expect it to work.
Do you actually know what you are mirroring? No! The default, hardcoded repo in Maven is Maven Central. It is a release repo which does not contain any snapshots. Therefore you see the ERROR. The bogus repo is necessary to enable Maven to request snapshots from your Nexus instance otherwise it will only request releases. Nexus in turn has a repo group with Central and your hosted release and snapshots repos.
As long as you don't define any snapshot repos in your POMs (which you shouldn't) Maven will never be able to download any snapshots.

Maven Release Patterns

I'm new to maven, and trying to understand how to release my project. I have the following project setup in svn:
trunk
|-deployer
| |-pom.xml
|-webapp
| |-pom.xml
|-utils
|-pom.xml
While developing webapp, I always want to develop against the latest snapshot version of utils, so I declare the dependency on utils in webapp/pom.xml via:
com.company
utils
1.0-SNAPSHOT
Webapp itself is also currently versioned at version 1.0-SNAPSHOT. It's pom.xml has the declaration:
<artifactId>webapp</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>Sample Webapp</name>
So everything is working great, but now I want to release my software. In deployer, I have the following in pom.xml:
<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.company</groupId>
<artifactId>deployer</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<name>Project Release</name>
<modules>
<module>externals/webapp</module>
</modules>
<properties>
<url.svn>http://<my-server>/<project>/trunk</url.svn>
</properties>
<scm>
<connection>scm:svn:${url.svn}</connection>
</scm>
<build>
<plugins>
<plugin>
<artifactId>maven-release-plugin</artifactId>
<version>2.3</version>
<configuration>
<tagBase>
http://<my-server>/<project>/tags
</tagBase>
</configuration>
</plugin>
</plugins>
</build>
<distributionManagement>
<repository>
<id>Releases</id>
<name>Releases</name>
<url>http://<nexus-server>/nexus/content/repositories/releases</url>
</repository>
<snapshotRepository>
<id>Snapshots</id>
<name>Snapshots</name>
<url>http://<nexus-server>/nexus/content/repositories/snapshots</url>
</snapshotRepository>
</distributionManagement>
</project>
Within the deployer folder itself I have a folder called "externals" which has an svn-externals set to check out my webapp project (I added this because maven complained about not being able to find it), so my modules path should be correct.
Questions
1.) I want to release a version of my web app, but when I run a mvn release:prepare and mvn release:perform in my deployer project, my only tangible output is my trunk tagged in svn and a pom uploaded to my nexus repository. This makes sense in that my deployer artifact packaging is type "pom", but it also doesn't get the job done of getting me a war of my webapp (I should note here that if a do a release in the webapp project by itself though, that I will get the war). I need to release multiple modules, and so I thought I could use maven aggregation from the deployer project to accomplish this, but it doesn't seem to be working.
2.) Is there a better way to achieve what I am trying to do?
Thank you for any insights you can provide.
You should run the maven-release-plugin against each module that you intend to release. I've never seen someone have a special "deployer" module that releases the other modules, this is not how things are commonly done.
Normally to release the webapp module you would run the commands against the webapp module, and to release the utils module you would run the commands against the utils module.
If you have a parent module that ties webapp and util together then I believe you can just run the release commands against that.
As matt b says, simply adding a maven-release-plugin entry at the top pom will probably do what you want. If you want to collect several artifacts into a proper release bundle, you want to create a module for this, but then you want to look at the maven assembly plugin. It can collect various jars (wether from modules or external dependencies) and resources into a directory, zip file or similar.

Categories

Resources