Can a module have the same artifactID as parent ? | Maven - java

I have a maven project of following structure:
parent (artifactID: ABC)
|
|---- module 1 (artifactID: ***)
|---- module 2 (artifactID: XYZ)
Can module 1 have artifactID: ABC?
My parent module is only meant to package the modules together. It doesn't have any source code of its own.
Does Maven take into account the hierarchy of modules to distinguish two modules? If not why?
It shouldn't be difficult to distinguish two guys with the same name but in different places.

When the groupId is identical, the artifactId must be different.
As the maven docs state, the groupId has to be universally unique and the artifactId must be unique within the groupId.
groupId
A universally unique identifier for a project. It is normal to use a fully-qualified package name to distinguish it from other projects with a similar name
artifactId
The identifier for this artifact that is unique within the group given by the group ID.

Sure - if the groupId is different :)
If the GAV is the same, then the artifact is the same and therefore your parent and artifact would be overwriting each other if you deploy them to say Artifactory or Nexus

Related

How to get only required dependency from parent dependency maven pom file

Can I include only the required dependencies from parent pom(like we have exclude)?
I need this to achieve one scenario
Project A with hibernate and spring as my dependencies(there are
many other)
Project B with only hibernate and spring
Project C with A and B as dependencies
Problem statement : when I run maven install in project C, hibernate and spring are again downloaded separately. This I observed because of the increase in final jar size.
As a work around I included project A as dependency in project C so that I don't need to mention hibernate and spring explicitly.
To avoid this is there a way to include only spring and hibernate from project A?
It sounds like you are guessing what's in the project C jar just based on size. Unzip the final jar (rename to .zip) and look inside to see what jars are actually being packaged to figure that out.
Jars, wars, ears are just zip files with a manifest (more or less).
So, your all dependencies should be defined in parent pom and all your projects here in case A, B and C should be child projects of the parent pom.
In all child poms, you can define all dependencies needed without versions, so that they will be resolved from parent pom.
Interdependency of child projects should be defined only in case of needed. This, to get just dependencies from project A, C should not depends on A.
| - - A
| - - | - - pom.xml
| - - B
| - - | - - pom.xml
| - - C
| - - | - - pom.xml
| - - pom.xml (parent pom)
If you could get this structure as github project, then I can create a pull request with the changes.
To Get Spring Hibernate from you need to make Child Parent relationship A(Parent) and B, C as Child.
Jar file increment mustn't be the case. POM.xml does provide reference of dependencies downloaded in .m2 repo.
For further investigation we need POM.xml

Maven `<module>` accepting many different relative paths

From maven doc :
modules/module* - List (Many) - The modules (sometimes called
subprojects) to build as a part of this project. Each module listed is
a relative path to the directory containing the module. To be
consistent with the way default urls are calculated from parent, it is
recommended to have module names match artifact ids.
But my little experimentation shows that it accepts a lot more than mentioned. It accepts ./artifactId also and artifactId also. It even accepts ./artifactId/pom.xml . Why ?
Has the doc missed the point of mentioning that we can provide relative path till pom.xml of that module too ?

The Uniqueness of an artifactId in maven

Let's say that there are 2 maven artifacts (local) with the same
groupId but with a different artifactId.
The different artifactId should make each maven artifact unique.
However, if both of the unique artifacts each have a class with that share the same name. that class will not be unique because when it is imported to java it will use the groupId.className format. and the neither groupId nor the className are unique (in the discussed case).
This will result in an issue of ambiguity as to determining which class to use.
Upon testing it seems that the dependency declared first in the pom.xml file will be used.
The Question Are
What is the best practice solve/avoid this issue?
Why does maven's artifactId coordinate contribute to the uniqueness of a maven artifact within the repository but not inside the java code?
Example Code:
Maven - Same Class Name Same GroupId Different ArtifactId
Project1 is the first artifact.
Project2 is the second artifact.
"Projects User" is the artifact/project that will depend on both Project1 & Project2.
Project1 & Project2 both have a class named Utilities.
The class Utilities have a static method public static String getDescription() that returns a string containing the current project's artifact coordinates as well as the project name.
Utilities.getDescription() resulting String is called to see if an error will occur somewhere, and to see how it will be resolved.
The output depends on which dependency was declared first in the pom.xml file of the "Projects User" artifact.
Edited : Follow up Question
Is there an archetype that will create the java package using both the artifactId and groupId instead of having to do it manually every
time?
What is the best practice solve/avoid this issue?
We include the groupId and artifactId as the base package in the module. This way it is not possible to have the same class in two modules as the packages would be different.
e.g.
<groupId>net.openhft</groupId>
<artifactId>chronicle-bytes</artifactId>
has everything under the package
package net.openhft.chronicle.bytes;
Also if you know the package of a class you know which JAR it must be in.
if you have a class two JARs need, I suggest creating a common module, they both depend on.
Note: it is general practice to use your company domain name (and notional division as well) as the base of your package. Maven recommend using your domain name as you groupId and if you release to Maven Central this is now a requirement. The above strategy supports both recommendations.
Why does maven's artifactId coordinate contribute to the uniqueness of a maven artifact within the repository but not inside the java code?
Maven doesn't take any notice of the contents of the JAR.
#Peter following your lead on suggesting best practices to avoid this issue.
Group Id : It is required to uniquely identify your project. Revese of your domain name ex :
com.github.dibyaranjan
artifactId is the name of the jar without version.
To distinguish two classes from different JARs, Create package as groupId.artifactId.
For Example, I would create a project TestDummy, I want the name of the JAR to be TestDummy-1.1, then my package would look like.
com.github.dibyaranjan.testdummy
The class would look like - com.github.dibyaranjan.testdummy.MyClass
For reference visit : https://maven.apache.org/guides/mini/guide-naming-conventions.html

Maven Plugin: accessing resources accross multiple modules

I'm currently writing a custom maven plugin for generating a XML file in a multi-module maven project.
My maven structure is pretty standard: one parent project and a module by project components in the parent project folder:
-- Parent
-- module A
-- module B
-- module C
I need to list, by module, a set of classes flagged by a custom annotation.
I already wrote a set of custom annotations and an annocation processor to create a XML file at compile time in the corresponding module output directory (${project.build.outputDirectory}) .
Now i need to merge each module XML into one file, but i don't know how to access each modules from within my maven plugin except having each path set as parameters (i don't like this method).
Any idea on how to do this ?
Does maven plugins can traverse project modules ?
Thank you in advance.
To get the list list of all projects you can use:
List<MavenProject> projectList = MavenSession.getProjectDependencyGraph().getSortedProjects()
If one of your goals is correctly executed you will get everything you need. Every MavenProject contains a getBaseDir() etc.
After some researches, it seems that MavenProject.getCollectedProjects() will return the list of projects beeing manipulated by a goal execution in a multi-module project.

Can maven projects have multiple parents?

We have Java and Flex projects. We currently have 1 base pom that contains the configurations we want to use for both projects. Problem with this is: Flex projects inherit configuration, for example, for javadoc and pmd plugins, which is not desirable.
I want to clean it up and have a real base pom, and then a java-base-pom and a flex-base-pom. But how does this work in a multi-module that has both a Flex part and a Java part?
We have plugins to our own application where we use the following structure:
my-plugin
my-plugin-client (flex)
my-plugin-server (java)
my-plugin just contains a pom.xml with <modules/> section. I would use my-plugin pom.xml as a parent for both, but then I cannot also use the java base-pom or the flex base-pom as parent. What would be the best approach for this?
Even though maven projects have single parent, they can import any number of other pom's like this:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>my-shared-dependencies</artifactId>
<version>0.0.1-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
This has two important differences compared to a parent:
Plugins defined in the imported pom won't be imported
Dependencies defined in the imported pom won't be added to the current pom, it will only import dependencies into the dependency management section
However, if your parent pom has a <dependencies> section and you want to include those into your dependencies, then you can add the parent to your <dependencies> section just like a regular dependency:
<dependency>
<groupId>org.example</groupId>
<artifactId>my-shared-dependencies</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
Even though the same dependency is already imported, the version tag has to be specified again. To reduce duplication, it can be stored in a property
A project can have only one parent (unlike multiple inheritance in C++) but this parent can be part of a bigger parent hierarchy. As pointed out by others, you could thus have something like this:
base-pom/
|-- flex-base-pom
| |-- my-plugin-client
| | `-- pom.xml
| `-- pom.xml
|-- java-base-pom
| |-- my-plugin-server
| | `-- pom.xml
| `-- pom.xml
`-- pom.xml
That said, I noticed you wrote that your actual problem is that:
flex projects inherit configuration for javadoc and pmd for example, which they do not want.
You should use the pluginManagement element to avoid this situation:
pluginManagement is an element that is seen along side plugins. Plugin Management contains plugin elements in much the same way, except that rather than configuring plugin information for this particular project build, it is intended to configure project builds that inherit from this one. However, this only configures plugins that are actually referenced within the plugins element in the children. The children have every right to override pluginManagement definitions.
So, in the parent pom, configure your plugins in pluginManagement (javadoc and pmd for example), and reference them within the plugins element in the desired children (only in my-plugin-server here). This would solve your current issue.
The only way is to have base-pom as parent of java-base-pom and flex-base-pom.
I have similar structure for my spring projects:
base-pom (basic configuration - eclipse, reports, repositories, etc)
|
+ spring-base-pom (spring definitions)
|
+ spring-jar-base-pom (jar specific definitions)
|
+ spring-war-base-pom (spring web and servlet dependencies)
|
+ spring-webapp-base_pom (spring web mvc dependencies)
I've cross this exact proble also, and the best solution I found was to use Inheritance and Aggregation as suggest in this question : does maven support multiple parents (multiple inheritance) ?
You can have an aggregator pom that is not the parent of the projects it
aggregates.
and explain in the Maven Documentation
Inheritance and aggregation create a nice dynamic to control builds through a single, high-level POM (...) Conversely, a POM project may aggregate projects that do not inherit from it.
From this I had my POMs inheritance (pom-master contains communes configurations, and each children the specifics ones) :
pom-master
|-- pom-java
|-- pom-flex
and so my project can get the specifics for each modules configurations as wished :
project (aggregate project-flex & project-java)
|-- project-java
| `-- pom.xml => parent = pom-java
|-- project-flex
| `-- pom.xml ==> parent = pom-flex
`-- pom.xml => parent = pom-master
Hope it will help others as well :)
Just image that pom.xml are in fact Java classes: you can have only one parent (or extends a class), but this parent can also have another parent, and so on.
As I explained here, you must distinguish the parent and aggregation principles in Maven, which means that my-plugin would be considered as an aggregation project, not necessarily a parent project for both my-plugin-client and my-plugin-parent.
So to summarize:
my-plugin will define the base pom for all your projects. Then, you create two new pom projects: java-base-pom and flex-base-pom. They have both my-plugin as parent. Now, my-plugin-client will have java-base-pom as parent, while my-plugin-server will use flex-base-pom for his parent.
This way, my-plugin-client will inherit all properties defined in the my-plugin pom.xml, and also from java-base-pom project.
You can achieve multiple inheritance with profiles:
You create (multiple) profiles in the root pom, and auto activate any variation of these profiles achieves multiple inheritance of maven configuration.

Categories