Gradle does not resolve transitive dependency inherited from parent pom - java

I was converting a maven project into a gradle project,but I encountered a problem.
Here is all i have:
project A;
Library B from third party, and also a dependency of A
Pom C, parent of B
Library D, a dependency of C
So, as expected, project A should have a direct dependency B, and a transitive dependency D
it works fine in maven form that project A can access library D.But in gradle form , gradle does not treat D as a dependency of project A,it just ignores this transitive denpendency.
`implementation 'group:B:version'`
How should it declear the depencency of B in gradle to get same result as in maven
I know it is not a regular way to access D from A without declearing dependency,but I just want to archive the same goal as maven with gradle.
Thanks for your answer ,any help will be much appreciated.

Use compile instead implementation in a both modules (A and B) if need to access to project C from project A.
P.S. This is not recommended and may indicate an incorrectly designed architecture. In particular, the violation of D from SOLID.

Related

How to reference local version of a project in another Gradle project dependencies

I have a Gradle project (say project A) that depends on another Gradle project (say B). Each project live in their own git repository. Sometimes when I have to make a non-trivial change across both projects, I will make the code changes in B and push to remote where our CI will pick it up and release it as a new version.
Then in project A, I will update the version for B with the new version number, then run ./gradlew generateLock saveLock and then I will be able to use the new changes made in B to implement the feature in A.
I want to avoid having to push B to remote and release a new version before I can start using the new code in A. Ideally, I want to make change to B locally and have A reference the local version of the project. That way I can test both and test the whole feature before I push any code. How can I achieve that using Gradle. I am using Gradle 7.5?
I declare my dependency on B in A's build.gradle as implementation 'com.something.project-b'. Note that B might have a bunch of other library dependencies of its own declared in its own build.gradle which should still be transitively pulled when I want to use the local version of B in A.
Any pointers?
There is a local JAR option in Gradle but that will not pull all the transitive dependencies of B and I do not want to build a combined JAR of B and all its dependencies and use that since then I lose all dependency resolution benefits in case of conflicts.
Also note that B is an independent project and cannot simply be moved to Project A as a sub-project
You don't need to do any sort of local workstation hodgepodge. All you need is the following:
Declare mavenLocal() as the first repository in the dependent project (you probably already have mavenCentral().
Publish the dependency to Maven local repository using the task .gradlew publishToMavenLocal.
Now, your dependent project can use the latest code from the dependency.
in the project 'A'
settings.gradle
include ':prjB'
project (':prjB').projectDir = new File(settingsDir, '../relativePath')
build.gradle
def prjBExists = file('path-to-prjB').exists
dependencies {
...
if (prjBExists) {
implementation project(':prjB')
} else {
implementation 'g:a:v'
}
}
PS - this referencing is under discussions as gradle-8 is expected to deprecate ...

Including dependency from imported maven library

A little fuzzy on Gradle/maven, but generally here is the idea.
I have a web application that uses a common library (A) as a dependency with source implemented under com.mydomain.utils package. There is another legacy package (B) written under a different namespace, com.mydomain.legacy, that I would like included within A, such that when I include A as a dependency in my primary application, library B's resources can be resolved as normal:
import com.mydomain.legacy.someutility
If B is a dependency of A, and A is a maven artifact, then B is already included in A, otherwise, it would not be possible to build A.
If B is not a dependency of A, then you need to list both A and B as dependencies of your project.

How to define qualified exports to unknown modules?

I have a Maven project with two Maven modules A and B. A contains the following Java module definition:
module A {
exports internal.util to B;
exports external.A;
}
B contains the following Java module definition:
module B {
requires A;
exports external.B;
}
When I build the project, I get an error:
[WARNING] module-info.java:[16,106] module not found: B
Module B exists but because Module A is compiled before B and does not depend on it, the compiler has no way of knowing that. Because I configured the compiler to treat warnings as errors (-Werror), the build fails.
Seeing as I want to keep treating warnings as errors, what is the best way to resolve this problem?
Is there a way to hint to the compiler that this module will be declared in the future?
Is there a way to suppress all warnings of this type?
I figured out a workaround by scanning through the JDK 11 source-code: -Xlint:-module. I am still open to a better solution if someone finds one.
UPDATE: An alternative is to use --module-source-path as demonstrated by https://stackoverflow.com/a/53717183/14731
Thank you Alan Bateman for pointing me in this direction!
As I could infer from the question, your scenario is such that both the module A and B co-exists and the module A does not depend on the module B.
From a module system prospect, since A makes a qualified export to the module B, a warning is thrown if the module B is not resolved on the modulepath while you build A.
On IntelliJ-IDEA I could fix such an issue by adding a dependency of module B to the module A without any declaration changes. Though using the Maven framework, I couldn't imagine something without a cyclic dependency here, maybe the suggestion by khmarbaise could help.
Note: An alternate way to fix this though could also be to disable such warnings using the command-line arg :
-Xlint:-exports
Or as Alan points out for correction
-Xlint:-module
Thinking out loud, that would be since, the warning is a result of a qualified export, but about a module not found.
Useful: You could find the details over these command line args with javac command.

How to solve circular dependency in gradle multi-project build

Consider the following situation. I have two gradle (sub-)projects called "A" and "B". A defines some classes/interfaces that are being referenced by B. So B has a compile dependency to A. Now A is a web server that should be started with B on the classpath. How do you achieve that with gradle?
Of course it is not possible to add B as compile dependency to A because that would mean a circular dependency between A and B. Even adding B as runtime dependency to A did not work because then compile errors in B state that referenced classes from A do not exist. But why?
One solution would be to move code from B into A but I really would like to separate that code because there might be another implementation of B later that I want to swap easily in A (e.g. by exchanging the jar in runtime classpath).
Another solution I was thinking about is to separate classes from A referenced by B into a new module and make both A and B depend on that new module. This sounds valid but that would imply to move persistence layer from A to that new module which feels wrong.
Additional information: A is a Spring boot web application with persistence layer, web services etc, B produces a JAR.
Circular dependencies are a well-known problem when you try to get Dependency Injection. In this case, you have something similar but at a module level
The only way I see you can solve your issue is by creating a third module C with the common code (probably the A interfaces referenced by B)
This way you can compile C (it doesn't have any dependencies), A (it depends on C), and B (it depends on C) and launch A with B in its classpath
Everytime you end up with circular dependency you probably should introduce another entity to break the cycle.
Have a look at my explanation in this other QA article (it's dealing with packages and classes, but idea is the same): What does it mean and how to fix SonarQube Java issue "Cycles between packages should be removed" (squid:CycleBetweenPackages)

Shade (relocate) one version of a transitive dependency, but not the other

I've got a Maven project that contains two dependencies, A and B. Each of these depends transitively on C, but they depend on different versions of C. Let's say that A depends on C version 1, and B depends on C version 2.
Unfortunately, A is not bytecode-compatible with version 2, nor B with version 1. (As it happens, A is source-compatible with version 2, but I don't think that will help us here.)
This means that I need both versions of the transitive dependency in my project, and I need A to use version 1, and B to use version 2.
Is there a way of doing this?
I had assumed that I would need to use the shade plugin to relocate the package name of A and all its dependencies, but this doesn't seem to be possible. If I shade A, its dependencies don't get shaded, and it still picks up version 2, and fails to run.
Create another project wrapper A named A-wrapper. Relocate C in A-wrapper.
Then in your main project, depends on A-wrapper and B.
I've met a similar problem on pb2 and pb3 and it is resolved using this way.
https://stackoverflow.com/a/41394239/1395722
Assuming dependency A requires v1 of C and dependency B requires v2 of C. You can create an uber jar of A containing v1 of C but changing the packaging using shade plugin,
Example jar A has contents of C with new packaging "v1.c.something". Do the same for B, so jar B has contents of C with new packaging "v2.c.something". You need to include only the conflicting dependencies not all.

Categories

Resources