How to solve Gradle Dependency inconsistencies in sub-modules? - java

Within my Gradle project I have many different versions of the same dependencies.
For example at my top level gradle build file I have declared a certain version of a dependency, but the sub-modules have delcared a different version.
Ideally I would like to have have the dependencies declared once at the top level so that all modules are using the same version of the dependency.
Is it possible to do this so that all sub-modules are using only the dependencies stated in the top level file?
If so, do I just update the top-level dependencies to the latest version and delete the dependencies declared within the sub-modules?

You can put all your dependencies in a project property in the main build file
ext.libraries = [
commons_io: "commons-io:commons-io:2.4"
, jasperreports: dependencies.create('net.sf.jasperreports:jasperreports:5.1.0') {
exclude group: 'com.lowagie'
exclude group: 'jfree'
}
, cxf: [
'org.apache.cxf:cxf-rt-frontend-jaxws:3.1.4'
, 'org.apache.cxf:cxf-rt-transports-http:3.1.4']
]
and then in the subproject build.gradle
dependencies {
compile libraries.commons_io
compile libraries.jasperreports
compile libraries.cxf
}

Well the simple answer is yes. Maven is also giving similar kind of facility where you should have one parent file where you can declare a < DependencyManagement > block and over there you can define all your dependencies.
Now, every child project or different modules are dependent on this parent project. So, these all modules have to declare dependency without the version, because we have declared this version in < DependencyMangement > block.
So, at the end what we say here is we are declaring the dependency at one location and using it where ever we need it.
Remember here that declaring dependencies in < DependencyManagement > blcok would not actually resolve the dependencies it will just declare it and child modules using < Dependency > can use that w/o defining version.

Related

How do I add a project as a dependency to my common.gradle?

I have a project structure that looks like the following:
-Root Project 1
settings.gradle
build.gradle
common.gradle <-Where my dependencies are declared
-SubProject A
.build.gradle
-SubProject B
.build.gradle
-SubProject C
.build.gradle
-Root Project 2
settings.gradle
build.gradle
common.gradle
-SubProject D
.build.gradle
What I'd like to do is add SubProject D as a dependency to RootProject 1, so that SubProjects A, B, and C can access it's classes. What do I change in the Root Project 1 build scripts to achieve this?
Currently the common .gradle declares dependencies like so
dependencies {
compile(group: 'com.software.core', name: 'ApplicationElements', version: '7.1.1-60')
}
However, that's referencing a jar from artifactory, in this case I would like to reference a local project instead.
You are using compile for your dependencies. That means you are using an outdated version of the Android gradle plugin. Newer version of the gradle plugin have introduced some concepts, to achieve exactly what you want.
If you are able to update to the latest Android gradle plugin (which I recommend to get other benefits such as much faster builds) you should use api:
api "com.software.core:ApplicationElements:7.1.1-60" // transitively add dependencies
vs
implementation "com.software.core:ApplicationElements:7.1.1-60" // do not leak module dependencies upwards
If you are NOT able to update the gradle plugin version, I recommend you read this page, which describes dependencies, both old and new styles.

Same interface in 2 different dependency issue

I have conflict problem with dependencies.
My project has two dependencies like this:
dependencies {
provided group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
compile files('path/to/ABC.jar')
}
ABC.jar has its own dependency to javax.servlet:servlet-api:
dependencies {
provided group: 'javax.servlet', name: 'servlet-api', version: '2.5'
}
Here is the problem I am dealing with; I need to use ServletContext interface which is provided by both servlet-api libraries and the compiler uses wrong one.
Gradle auto-resolves version conflicts as described here.
But in my case it doesn't help, because it only works when a dependency has two different versions. In this case; although it's a newer version issue, the name has changed from javax.servlet:servlet-api to javax.servlet:javax.servlet-api. So gradle doesn't auto-resolve this conflict, because it doesn't seem to be a version issue.
The thing I tried was using excluding transitive dependency as described here.
compile files('path/to/ABC.jar') {
exclude group: 'javax.servlet'
}
But it didn't work, it seems exclude doesn't work on local 'jar' files.
Now, I don't know what else to do.
How can I exclude a dependency of a dependency which is added as a local file?
(If the first question doesn't have any answer yet) How can I say to the compiler to use the correct ServletContext interface?
compile files('path/to/ABC.jar') is a file dependency, a file dependency does not have any dependency information, so it does not introduce transitive dependencies. If this ABC.jar is a "fat" jar that has the dependency-classes included in the JAR, it is not suited for usage in something like Gradle, Maven or Ant/Ivy that is supposed to handle the dependencies. You would have to use a proper "thin" version of the dependency with the dependencies properly declared, or you need to "repackage" that JAR in your build script to exclude the dependency classes you don't want to pull in. No dependency management can do this for you.
You can execute gradlew dependencyInsight --configuration runtime --dependency javax.servlet:servlet-api or gradlew dependencies --configuration runtime to find out where the dependency really comes from.
Actually your example should not even compile if I see it correctly, because it should most probably be
compile files('path/to/ABC.jar'), {
exclude group: 'javax.servlet'
}
or
compile(files('path/to/ABC.jar')) {
exclude group: 'javax.servlet'
}
But as I said, with a local file dependency there are no transitive dependencies, so an exclude does not make sense at all anyway.
To make the Gradle version conflict magic work, you can simply tell Gradle that those libraries are actually the same library just with different coordinates by using a module replacement like
dependencies {
modules {
module('javax.servlet:servlet-api') {
replacedBy 'javax.servlet:javax.servlet-api'
}
}
}
Then Gradle sees them as the same library and can do its version conflict resolution magic. Whether the library that needs the old version still works with the new version is a different topic that you have to check and / or try yourself. This like always depends on whether the new version is backwards compatible to the old version.
I have no way to test this now, but I believe your syntax is wrong. I have some examples here that look different, in your case it would be:
compile(files('path/to/ABC.jar')) {
exclude group: 'javax.servlet'
}
As I say, I cannot test it now, check if it helps and give a comment.

How to specify "pig-0.13.0-h2.jar" dependency in build.gradle?

To specify a Maven dependency in my project, I provide a name, a group id, and a version. This has been enough for every dependency in my project, save one. Pig has multiple jars in the same artifact (not sure if I have the proper nomenclature; I'm still rather new to Maven), but I only need one.
Specifically, I need pig-0.13.0-h2.jar. However, when I provide the dependency
compile "org.apache.pig:pig:0.13.0"
in my build.gradle, only pig-0.13.0.jar, pig-0.13.0-sources.jar, and pig-0.13.0.pom are downloaded. I need the "*-h2.jar", because that's the correct one to work with my version of Hadoop.
Is there a way to tell Gradle (and, generally, Maven or whatever) that my compile dependency requires this exact jar, and that only this one should be included in the classpath?
What you need is to specify the classifier. The following script will do the job:
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
compile "org.apache.pig:pig:0.13.0:h2"
}
task copyDeps(type: Copy) {
from configurations.compile
into 'deps'
}

How do you configure the default dependencies in a new Gradle project in IntelliJ Idea

After I added some dependencies to build.gradle
compile(
"org.springframework.boot:spring-boot-starter-web:1.1.6.RELEASE",
"org.springframework:spring-core:4.1.0.RELEASE",
"org.springframework:spring-test:4.1.0.RELEASE",
"javax.inject:javax.inject:1",
"org.mockito:mockito-all:1.9.5",
"org.quartz-scheduler:quartz:2.2.1",
"org.apache.commons:commons-lang3:3.3.2",
"com.google.guava:guava:18.0"
)
and refreshing the IntelliJ Gradle plugin, many more dependencies appear in the Gradle libs list inside "External Libs"
I suspect this is nothing to do with the plugin, but rather gradle augmenting my dependencies from somewhere else but I can't work out from where.
Just like in Maven, the dependencies you declared can have further dependencies that are declared by the package supplier (a.k.a transitive dependency management) - those will be added automatically, just like you observed.
More info here.

This dependency gives me two versions of one jar. How do I fix this?

I'm using Gradle for my project. One of the dependencies I have specified in my build.gradle is
compile 'org.glassfish.jersey.media:jersey-media-moxy:2.0'
This works fine on a normal Java application, however when I try to build it on Android I get:
When looking at which libraries are referenced, it's clear that there's both javax.inject-2.3.0-b05.jar and javax.inject-1.jar, which I found are added by the dependency above. I'm guessing that this 'duplicate' jar is what causes the build error.
How do I go around this? Why does the dependency include two of the same jar? Is there a way to either make the Android version build with these two jars or to remove one of these jars?
It appears that you have a dependency tree akin
project
|--- org.glassfish.jersey.media:jersey-media-moxy:2.0
| \--- *:javax.inject:1
\--- *:javax.inject:2.3.0-b05
Where * is the group, which I suspect may be different from those two.
Try getting an idea of how your dependencies are being grabbed by using the dependency task
gradle dependency
Should you need to exclude a dependency enter it in the tag, similar to the below example
compile('org.hibernate:hibernate:3.1') {
//excluding a particular transitive dependency:
exclude module: 'cglib' //by artifact name
exclude group: 'org.jmock' //by group
exclude group: 'org.unwanted', module: 'iAmBuggy' //by both name and group
}
Normally gradle will only include 1 jar per dependency. If different version found for the same depedencies, the newer version will be used.
However, in your case, these 2 jars are dependencies with different group names:
'javax.inject:javax.inject:1'
'org.glassfish.hk2.external:javax.inject:2.3.0-b05'
That's why gradle included both as they are treated as different dependencies.
'javax.inject:javax.inject:1' is very old, I think you should exclude it like what Niels Bech Nielsen said.
To find out where is this dependency come from , you can use command:
gradle -q dependencyInsight --dependency inject

Categories

Resources