gradle earlib not pulling transitive libraries - gradle

I got gradle 3.5.1 and using ear plugin. The documentation says that deploy configuration is not transitive but earlib actually is (https://docs.gradle.org/3.3/userguide/ear_plugin.html). My configuration is a below
dependencies {
earlib(
"org.mybatis:mybatis:3.2.8"
)
}
It was supposed to get a few other transitive libraries but here is all I get when I run gradle dependencies
earlib - Classpath for module dependencies.
\--- org.mybatis:mybatis:3.2.8
What am I doing wrong here?

Actually, you are doing nothing wrong. Your module dependency org.mybatis:mybatis:3.2.8 simply does not define any (mandatory) transitive dependency, since every compile or provided dependency is marked as optional.
According to the Maven docs,
If a user wants to use functionality related to an optional dependency, they will have to redeclare that optional dependency in their own project.

Related

How to excplude module cxf-rt-transports-http

I have the following dependency in build.gradle:
compile ('org.apache.cxf:cxf-bundle:2.4.2') {
exclude module: 'log4j-over-slf4j'
}
I would like to also exclude the module that contains transports-http because of a conflict between libraries (using HTTPConduit). I tried to exclude it, but I don't think I have the right module name
The dependencies task will give you a dependency report where you can see what transitive dependencies are being pulled in.
./gradlew dependencies --configuration compileClasspath
If you were to examine the output of that task, you'll see that org.apache.cxf:cxf-bundle does not appear to bring in cxf-rt-transports-http. So you'll need to examine your project to figure out where the duplicate dependency is.
Gradle also offers a means to handle version conflicts as well: https://docs.gradle.org/current/userguide/viewing_debugging_dependencies.html#sec:resolving-version-conflict

Gradle plugins' transitive dependencies interfering and breaking the build

I am using Gradle 6.1 in a multimodule project. I am also using two plugins: kotlin("jvm") and id("com.google.cloud.tools.jib"), and they are loaded in the following modules:
root/
build.gradle.kts loads kotlin("jvm")
services/
my-service/
rest/
build.gradle.kts loads id("com.google.cloud.tools.jib")
(There are more modules, files etc. but these are the relevant ones.)
The build fails:
$ ./gradlew clean jibDockerBuild
...
* What went wrong:
Execution failed for task ':services:driver:rest:jibDockerBuild'.
> com.google.cloud.tools.jib.plugins.common.BuildStepsExecutionException: 'org.apache.http.client.config.RequestConfig$Builder
org.apache.http.client.config.RequestConfig$Builder.setNormalizeUri(boolean)'
I identified the issue: both the Kotlin and JIB plugins have a transitive dependency on org.apache.httpcomponents:httpclient: Kotlin requires 4.5.3 and JIB 4.5.10. The problem is, in this project setup only 4.5.3 is loaded, and JIB fails as the new method is not available. This can be checked with ./gradlew buildEnv.
I've found a workaround, I need to load both plugins at the root level (which one is first seems to be irrelevant) in the main Gradle file; now ./gradlew buildEnv shows that the higher dependency version is used, also for Kotlin (output shortened and incomplete):
classpath
+--- org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:1.3.61
| \--- org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.61
| +--- de.undercouch:gradle-download-task:3.4.3
| | \--- org.apache.httpcomponents:httpclient:4.5.3 -> 4.5.10
It works in this case, but it could be that the new library version breaks the Kotlin plugin. The problem is that the plugins and their dependencies are on the classpath without separation, something that was normal on Java before Jigsaw etc. Is there any way for Gradle to be able to separate the dependencies so that each plugin uses exactly the version it declares? I am building on Java 11, so the module system could be utilized, but does Gradle have an option to turn it on?
EDIT: updating to Kotlin 1.3.70 also fixes the issue as it doesn't depend on the library any longer. The general question is still valid, though.
Is there any way for Gradle to be able to separate the dependencies so that each plugin uses exactly the version it declares
No.
All plugins share the same build script configuration: classpath
It follows the same dependency resolution that application dependencies follow. So you can enforce that for this particular dependency only use a specific version always:
buildscript {
configurations {
classpath {
resolutionStrategy {
force("org.apache.httpcomponents:httpclient:4.5.10")
}
}
}
}
That's just one of many ways you can take control of dependency resolution for build script dependencies. You could also use a platform to advise on the dependency versions:
buildscript {
dependencies {
classpath(enforcedPlatform("org.springframework.boot:spring-boot-dependencies:2.2.5.RELEASE"))
}
}
Refer to the docs for more info:
https://docs.gradle.org/current/userguide/resolution_rules.html
https://docs.gradle.org/current/userguide/platforms.html

Maven and Gradle nested dependencies

I have a library A that uses a library B. These two libraries are then used by application C.
Both library A and B can be found in a maven repository.
I have tried to add B as a dependency to A by adding it into A's POM file.
I'm not sure if this is the correct approach or there is a standard way to do this.
I am looking for either the standard way of doing this or a reference guide to point me into the right direction.
Please let me know if there is any other information I can provide.
The term for such relationship is called a transitive dependency. In your application, you define just the direct dependencies, the transitive ones are handled by a particular build system (Gradle, Maven, Ant + Ivy).
For example, considering following Gradle build script:
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.0.2'
}
You can list this project dependencies with the command:
$ gradle dependencies
This should provide result similar to (depends on the Gradle version, this one is 4.4.1):
testCompileClasspath - Compile classpath for source set 'test'.
\--- org.junit.jupiter:junit-jupiter-api:5.0.2
+--- org.opentest4j:opentest4j:1.0.0
\--- org.junit.platform:junit-platform-commons:1.0.2
Therefore, opentest4j and junit-platform-commons are transitive dependencies of the junit-jupiter-api library, which is the only direct dependency of the project.
It's equivalent for Maven. E.g. you can list Maven dependencies with:
$ mvn dependency:tree

Determine source of transitive dependency

I have a project in which I am using sl4j with log4j. I recently added a few new dependencies to my project, and one of these new dependencies that I added is including a transitive dependency to logback-classic, which includes another binding for sj4j.
I want to get rid of logback, but I have no clue which of my direct dependencies added the transitive dependency so that I can exclude it.
In maven I know how to get the entire graph of dependencies to determine which is the source of a transitive dependency, but I have no clue of how to do this with gradle.
Does anyone knows how to get the source dependency of a transitive dependency with gradle?
To show the whole dependency tree for each class path, use:
> gradle dependencies
If you are only interested in a particular class path, use (say):
> gradle dependencies --configuration compile
Use the -p option to run on a sub-project.
To show who pulls in a particular dependency onto a particular class path, and how any version conflicts were resolved, use (say):
> gradle dependencyInsight --dependency logback --configuration compile
Note that you can also exclude a dependency from a whole class path (or multiple). Usually this is more reliable than excluding a particular transitive dependency. For example:
configurations.all*.exclude module: "logback-classic"
An updated answer:
I used this code to resolve a dependency issue between logback and log4j:
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute module('org.apache.logging.log4j:log4j-slf4j-impl') using module ('ch.qos.logback:logback-classic:1.2.3')
}
}
This solution finds any dependencies on log4j-slf4j-impl and instructs it to choose the one from logback (this is a spring app). This solution was surprisingly difficult to track down, but likely very useful in many situations.
Here's the gradle documentation on handling conflicting candidates.

Gradle doesn't include transitive dependencies

I'm trying to use spring-test-mvc for testing a controller in my little application. Since I use gradle as build tool I added the dependency to it like this:
testCompile 'org.springframework:spring-test-mvc:1.0.0.M1'
It succeeds to retrieve spring-test-mvc, and compile the tests. But executing the tests fails, because it doesn't seem to include transient dependencies like mvc test.
Among others it complains about not finding
org.springframework.mock.web.MockHttpServletRequest
Which is part of the spring-test.jar, which is included as a dependency in spring-test-mvc s pom.xml https://github.com/SpringSource/spring-test-mvc/blob/master/pom.xml
I can fix that problem by including the dependency explicitely in the build file:
testCompile 'org.springframework:spring-test:3.1.1.RELEASE'
But it just gets replaced by the next problem. I tried to explicitly ask for transient dependencies:
testCompile ('org.springframework:spring-test-mvc:1.0.0.M1') {
transitive = true
}
But that doesn't seedm to change anything.
So the question is: How do I get gradle to include transitive dependencies in the classpath.
Note: Transitive dependencies seem to work fine outside of tests.
It's a problem with the POM. http://repo.springsource.org/libs-milestone/org/springframework/spring-test-mvc/1.0.0.M1/spring-test-mvc-1.0.0.M1.pom does not declare any dependencies.

Resources