Maven parent POM: Circular dependencies
circular-dependency, dependency-management, maven
Solution
Suggestion
For simplify dependency configuration use versions ranges.
For example artifact `A` needs artifact `B` with version `0.1.0`. Configure dependency as range `<version>[0.1.0, 0.2.0)</version>`.
This mean that `A` requires `B` with version greater or equal than 0.1.0 and less than 0.2.0 (so all hotfixes are good for this artifact).
This helps, because when hotfix is released, there is no need to change artifact `A` dependencies. Just rebuild parent project and hotfixed `B` will be attached to project `A`
This technique requires releasing parent project when hotfix is released By parent project I mean somethink like WAR with libraries or EAR, or Distribution Archive with all artifacts inside.
More: 3.4.3. Dependency Version Ranges
Problem
We have a modular project with about 10 artifacts: ``` parent +- artifact1 +- artifact2 +- artifact3 +- ... +- artifact10 ``` Furthermore, some of the artifacts have dependencies among each other: ``` artifact1 +-> artifact2 +-> artifact3 +-> ... +-> artifact10 artifact2 +-> artifact3 artifact4 +-> artifact3 artifact4 +-> artifact5 artifact5 +-> artifact6 ``` Our current setup looks like this: - parent is an artifact containing the parent POM. - This parent POM defines all necessary dependencies (like Spring, JPA, ...) in . - All of our artifacts are defined in , too. - Our artifacts reference the parent artifact as - stating the obvious - parent. - Only the parent POM defines versions. All other POMs don't. We use a versioning scheme with three numbers: ``` <major version>.<minor version>.<patch level> ``` For example: ``` 0.1.0-SNAPSHOT (a young artifact in development) 0.1.0 (the same artifact once it has been released) 0.1.1 (the same artifact after a hotfix) ``` The problem: Once we change the version of an artifact (e.g.: 0.1.0 => 0.1.1), our parent artifact version (12.7.3) needs to be updated because it references the old artifact version (0.1.0). Since we change this reference in the parent POM (0.1.0 => 0.1.1), we need to increase the parent POM's version, too (12.7.3 => 12.7.4). Now, our artifact still references the previous parent version (12.7.3), i.e. we need to update it again... That's circular. What is the best way to resolve such circular parent-child relationships? We could remove our own dependencies from the parent POM and define their versions in all of the other artifact's POMs but this implies that we would need to update all artifacts once a dependency changed. EDIT A simplified directory structure that contains our artifacts: ``` . ├── [api:0.14.0-SNAPSHOT] │ ├── pom.xml │ └── src │ ├── main │ │ ├── java ... │ │ └── webapp ... │ └── test ├── [dao:1.21.0-SNAPSHOT] │ ├── pom.xml │ └── src │ ├── main ... │ └── test ... ├── [parent:0.11.0-SNAPSHOT] │ ├── pom.xml │ └── src │ ├── main ... │ └── test ... ├── [pdf-exporter:0.2.0-SNAPSHOT] │ ├── pom.xml │ └── src │ ├── main ... │ └── test ... ├── [docx-exporter:0.3.0-SNAPSHOT] │ ├── pom.xml │ └── src │ ├── main ... │ └── test ... ├── [exporter-commons:0.9.0-SNAPSHOT] │ ├── pom.xml │ └── src │ ├── main ... │ └── test ... └── [security:0.6.0-SNAPSHOT] ├── pom.xml └── src ├── main ... └── test ... ``` The artifact directories (in square brackets; along with the artifact version) are independent from each other, i.e. they are only in a common root directory (".") for convenience. Every artifact has its own git repository. "api" is the artifact that gets deployed on an application server. All artifacts reference "parent" like this (during development): ``` <parent> <groupId>com.acme</groupId> <artifactId>parent</artifactId> <version>0.11.0-SNAPSHOT</version> </parent> <artifactId>api</artifactId> <version>0.14.0-SNAPSHOT</version> ``` Scenario: - exporter-commons gets an update: 0.9.0-SNAPSHOT => 0.9.1-SNAPSHOT. - docx-exporter and pdf-exporter reference exporter-commons without version, i.e. no change is necessary. - parent needs to be updated to reflect the update of exporter-commons: 0.11.0-SNAPSHOT => 0.12.0-SNAPSHOT. Problem: api:0.14.0-SNAPSHOT references parent:0.11.0-SNAPSHOT. api:0.14.0-SNAPSHOT is then updated to reference parent:0.12.0-SNAPSHOT. api:0.14.0-SNAPSHOT becomes api:0.15.0-SNAPSHOT. But the pom.xml in parent:0.12.0-SNAPSHOT references api:0.14.0-SNAPSHOT. => Vicious circle. (Note: The artifact names are made up for simplicity.)