Question about source dependencies scenario

Greetings, I would like to ask about source dependencies in Gradle.
Suppose I had three separate projects: A, B, and C.
As A depends on B with version 1.0 and on C with version 1.0, but C depends on B with version 1.1, dependency resolution will result in project B with version 1.1.
Imagine that I combine projects A and B under the same root project, so A now has a source dependency on B, but C still brings B with version 1.1. How does Gradle handle this scenario? Does it recognize that it is the same artifact? Does it consider it a higher version?
In the documentation, I was unable to find an explanation of this scenario.

Hello @matans

i am new to gradle but this what i found about version conflict

https://docs.gradle.org/current/userguide/dependency_resolution.html#sec:version-conflict

also check
https://docs.gradle.org/current/userguide/single_versions.html

https://docs.gradle.org/current/userguide/rich_versions.html
https://docs.gradle.org/current/userguide/dynamic_versions.html
https://docs.gradle.org/current/userguide/dependency_locking.html

hope those help and have a nice day :slight_smile:

It’s been a long time since I looked at such “circular” dependency trees, but last time I did I observed that Gradle does version conflict resolution the same regardless of whether the module is a local project or an external module. So if the local project had a lower version than the external module then the external module would be selected. If thy have the same version I’m not sure which one wins.

My personal opinion; this type of “circular” dependency tree is an indicator that the modules may not be well organized and could need some refactoring. It hints that there could be too much coupling between the separate modules and that they should all be in the same project, or at least parts of them.

1 Like

Where do you see a dependency circle @Chris_Dore?

A
 > B 1.0
 > C 1.0
    > B 1.1

Regarding the conflict resolution I think it is exactly the other way around.
Iirc source dependencies are the Git-management wrapper around a composite build.
So the source dependency feature makes sure the Git-project of the dependency is cloned and checked out properly and then includes the build to form a composite build.
An included build should always win, no matter which version is declared if I’m not completely mistaken.
So actually I think the source dependency will win and be used.
But I might be wrong. Just try it out and share the result here for others to learn. :slight_smile:

It’s technically not a dependency loop, unless you look at it from just a module perspective, B->C->B. I was trying to suggest that there’s a code-smell there, not a technical problem, at least in my opinion. If you had no binaries and tried to build these projects from source you would be stuck. To me that’s an architectural problem and I suggest the module loop be broken if possible.

I think @matans was talking about a multi-project build when saying, “combine projects A and B under the same root project, so A now has a source dependency on B”, but I could be mistaken. @matans, could you clarify if you are using a multi-project build, composite build, or source dependencies? These are all different concepts in Gradle.

I would love to hear what happens as well @matans. My knowledge on how the conflict resolution behaves in your scenario is based on behaviours observed 5 or 6 years ago.

It’s technically not a dependency loop, unless you look at it from just a module perspective, B->C->B.

To be honest, I still don’t see where.
B is not depending on C.
A is depending on B as well as on C.
C is depending on B too.
But that is just normal situation, not a smell.
Unless I got something wrong.

If I would see the loop you see, I would fully agree to break it.

Oh wow!! Sorry all, I somehow got things all wrong in my head and even missed my mistake when @Vampire rendered the dependency tree.

Ignore what I said about there being a loop.

There’s probably a lesson here about working too late :joy:

1 Like

Thanks for all of your replies… Please allow me to explain a real use-case that will provide you with a better understanding of the situation demonstrated.

For example, consider a multi-project titled “Service” that consists of two subprojects: “server” and “api” (which correspond to A and B in my example). “server” and “api” share the same version. Project “C” which is a completely separate project, depends on the “api” project with version “1.1”. Does Gradle handle module “api” differently or does it look at the “api”'s version as a source dependency like a normal one?