Gradle doesn't include transitive dependencies - gradle

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.

Related

Converting a transitive dependency into a compileOnly dependency

I am trying to use OSGI to allow me to use two different versions of a transitive dependency. The plan is that one version (the newer version) will be hidden away inside an OSGI bundle, the other will be on the runtime classpath as normal.
I have built the bundle jar using Gradle (with the Groovy DSL), but the problem is its associated runtime dependencies are wrong - it brings along the newer version, which is supposed to be hidden inside the bundle. This is still true when I do, in the build.gradle file:
compileOnly deps.diffx
runtimeOnly(deps.diffx) {
exclude group: 'com.propensive', module: 'magnolia_' + versions.scala_v
}
If I examine the dependencies with the Gradle dependencies task, it shows that magnolia is excluded from the runtimeOnly configuration, as expected - but is not excluded from the runtimeClasspath configuration.
If I then use ./gradlew dependencyInsight --dependency magnolia_2.12 --configuration runtime to try to find out where this dependency is coming from, it tells me that the newer version is coming from runtimeClasspath depending on diffx, and this is selected via conflict resolution. Well thanks - I already knew that. The question is, why is my exclusion not being applied to the derived configuration?
Basically I want to do the opposite of this question.
I also tried constraint versions, but they exhibited the same problem:
compileOnly deps.diffx
runtimeOnly(deps.diffx) {
constraints {
implementation('com.propensive:magnolia_' + versions.scala_v + ':0.10.0') {
because 'this version is required by our other dependencies'
}
}
}
From the Gradle documentation:
On the upside, Gradle’s exclude handling is, in contrast to Maven, taking the whole dependency graph into account. So if there are multiple dependencies on a library, excludes are only exercised if all dependencies agree on them. For example, if we add opencsv as another dependency to our project above, which also depends on commons-beanutils, commons-collection is no longer excluded as opencsv itself does not exclude it.
So instead, we can use a dependency resolve rule:
def magnoliaVersion = '0.10.0'
configurations.runtimeClasspath {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'com.propensive' && details.requested.name.startsWith("magnolia_") && details.requested.version != magnoliaVersion) {
details.useVersion magnoliaVersion
details.because 'this version is required by our other dependencies'
}
}
}
and then change the dependency back to a simple, single implementation one:
implementation deps.diffx
Unfortunately, as the documentation notes, this resolve rule isn't published, so it has to be applied again in any dependent Gradle modules.

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 earlib not pulling transitive libraries

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.

Gradle trump providedCompile's exclusion?

I've got a project that I want to use providedCompile with to avoid pulling it's libs. However, that prevents me from pulling in another project's libs that I do need. The docs say: If you don't want this transitive behavior, simply declare your provided dependencies, but it doesn't give an example of how to do this.
Here's basically what my dependencies look like:
dependencies {
compile(project(':common'))
providedCompile(project(':projA')) // <-- also depends on :common
}
My war file correctly excludes all of transitive libs from projA, but I need to trump that for the common.jar and I can't figure out how to make that happen. But the docs seem to indicate it's possible...
Edit: Here's a hacky configuration that seems to work. The combination of lines for "projA" gives me projA.jar as a dependency, but not its children. And since "common" is a compile dependency, but "projA" is only considered provided at runtime, I still get the common.jar due to the compile time dependency. I'm not sure it's supposed to work this way, but it generates the war I need.
dependencies {
compile(project(':projA')) { transitive = false }
providedRuntime(project(':projA')) { transitive = false }
compile(project(':common'))
}
If you don't want this transitive behavior, simply declare your provided dependencies
This means that if you don't want all dependencies of projA to be declared provided you need to list them as provided one by one.
From the Gradle 1.8 Userguide '26.4. Dependency management'
The War plugin adds two dependency configurations: providedCompile and
providedRuntime. Those configurations have the same scope as the
respective compile and runtime configurations, except that they are
not added to the WAR archive. It is important to note that those
provided configurations work transitively.
Let's say you add commons-httpclient:commons-httpclient:3.0 to any of
the provided configurations. This dependency has a dependency on
commons-codec. This means neither httpclient nor commons-codec is
added to your WAR, even if commons-codec were an explicit dependency
of your compile configuration. If you don't want this transitive
behavior, simply declare your provided dependencies like
commons-httpclient:commons-httpclient:3.0#jar.
There is another better solution that seems to be working. With transitive=false you exclude all the transitive dependencies that are then missing during compilation time and you have to declare all of them manually (again as provided) which is pain if they also include your desired library.
So for the providedCompile statement exclude not all transitive dependencies but only the one you want to include in war by separate compile statement.
Real example where I need the commons-codec included in the war file but that one is placed also in the keycloak-services and keycloak-model-jpa:
providedCompile ("org.keycloak:keycloak-model-jpa:6.0.1") {
exclude group: 'commons-codec', module: 'commons-codec'
}
providedCompile ("org.keycloak:keycloak-services:6.0.1") {
exclude group: 'commons-codec', module: 'commons-codec'
}
providedCompile "org.keycloak:keycloak-core:6.0.1"
providedCompile "org.keycloak:keycloak-server-spi:6.0.1"
providedCompile "org.keycloak:keycloak-server-spi-private:6.0.1"
compile "commons-codec:commons-codec:1.10"

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.

Resources