Dependency management between modules - java

If I have module A and module B that both needs a JSON library (say GSON),
and then I have application C which includes module A & B. There is a chance I will get two different versions of the JSON library if module A and B use different versions? Or does gradle remove one of them and just use one of the versions?
What if I have even more modules, updating them to use the same version of a dependency seems like a lot of work. In this case, letting Application C decide which version to use over all modules would be nice (but not always working I guess because of backwards compatability). Anyway to achieve this?
So my questions is how to best handle dependencies which are very common in many modules. Should I have a Json wrapper that I inject in all my modules instead, letting the Application define what to use?
I guess logging could be a similar dependency

Yes. If you specifically ask for different versions of the same library in projects A and B, you might end up with different versions of the same direct dependency.
As to transient dependencies, the default behaviour is to settle on the newest version of the requested dependency. Please mind the word newest as opposed to highest version requested. This is fine as long as the versions are backward compatible with the lowest version your project actually expects.
Luckily, gradle has several built in methods to settle dependency conflicts.
I have written extensively on the subject here: http://www.devsbedevin.net/android-understanding-gradle-dependencies-and-resolving-conflicts/
TL;DR
You may choose to fail on conflicts:
configurations.all {
resolutionStrategy {
failOnVersionConflict()
}
}
Force a specific dependency:
configurations.all {
resolutionStrategy {
force 'asm:asm-all:3.3.1', 'commons-io:commons-io:1.4', 'com.parse.bolts:bolts-android:1.+'
}
}
Prefer your own modules:
configurations.all {
resolutionStrategy {
preferProjectModules()
}
}
Replace all instances of libary X with Y (either a library, a module or a project):
configurations.all {
resolutionStrategy {
dependencySubstitution {
substitute module('commons-io:commons-io:2.4') with project(':my-commons-io')
}
}
}
Exclude all transient dependencies for a specific library and add the necessary libraries by manually:
dependencies {
compile('com.android.support:appcompat-v7:23.1.0') {
transitive = false
}
}
Exclude a specific transitive dependency:
dependencies {
compile('com.android.support:appcompat-v7:23.1.0') {
exclude group: 'com.parse.bolts'
}
}
Force your project to use a specific version regardless of the actual dependency requirements:
dependencies {
compile('com.parse.bolts:bolts-android:1.+') {
force = true
}
}

Consider a Gradle build that has two modules/projects. The settings.gradle file:
include 'modA', 'modB'
Let's say that both use commons-lang3-3.6, and modA uses gson-2.8.1, whereas modB uses gson-2.2.4. One could configure this in the build.gradle file at the root:
subprojects { p ->
apply plugin: 'java'
repositories {
jcenter()
}
dependencies {
compile 'org.apache.commons:commons-lang3:3.6'
}
if (p.name == 'modA') {
dependencies {
compile 'com.google.code.gson:gson:2.8.1'
}
} else if (p.name == 'modB') {
dependencies {
compile 'com.google.code.gson:gson:2.2.4'
}
}
}
The desired config can be confirmed with:
$ gradle :modA:dependencies
$ gradle :modB:dependencies

Related

Gradle composite build can't resolve transitive dependencies [duplicate]

This question already has answers here:
What's the difference between implementation, api and compile in Gradle?
(12 answers)
Closed 1 year ago.
I have a project A which depends on library B, I am using gradle composite builds.
Project B contains several common dependencies such as "org.apache.commons:commons-lang3"
Project A uses "org.apache.commons:commons-lang3" as well but transitive dependencies resolution does not work as I would expect, I have to declare again "org.apache.commons:commons-lang3" in the dependencies block of project A build.gradle in order to make it work.
Project A build.gradle:
group = 'org.example.app'
version = '0.1.0'
plugins {
id 'java'
id 'application'
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(11))
}
}
dependencies {
implementation 'org.example.libs:B'
}
Project A settings.gradle
includeBuild '../../libs/B'
Project B build.gradle:
group = 'org.example.libs'
version = '0.1.0
plugins {
id 'java-library'
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(11))
}
}
dependencies {
implementation 'org.apache.commons:commons-lang3:3.12.0'
}
repositories {
mavenCentral()
}
Project B compiles well as standalone but I can't compile project A without adding again
"org.apache.commons:commons-lang3:3.12.0" in its build.gradle. Isn't it supposed to be resolved as transitive dependency from project B ?
Project A Compilation throws errors such as :
error: package org.apache.commons.lang3 does not exist
What am I missing ?
This probably has been answered many times, but I cannot find a good answer.
To make transitive dependencies available, you have to use api rather than implementation in project B.
dependencies {
api 'org.apache.commons:commons-lang3:3.12.0'
}
If you have previous experience with maven, you'll need to unlearn a lot of stuff as gradle is a very different beast and reading the manual is well worth it (even if it's a bit tedious)

How to generate all-projects-in-one Gradle project?

I have a gradle monolithic project with too many dependencies.
I'd like to explode it into many sub-projects and publish all sub-projects (build + sources + javadoc) + an extra project being the merge of all sub-projects.
This extra project should be like a virtual artifact with all my projects in a single jar like it is today because I don't want a too big change for my users.
The jar must not include dependencies (it is not an uber-jar) but the resulted pom.xml must contain the dependencies of all sub-projects (the generated pom.xml of the maven artifact must contain all dependencies).
The virtual artifact will include the merge of javadoc and sources too in order to respect Maven Central conventions.
Current state:
Project Main, generate
pom.xml
main.jar
main-sources.jar
main-javadoc.jar
Expected state:
Subproject A, generate
A-pom.xml
A.jar
A-sources.jar
A-javadoc.jar
Subproject B, generate
B-pom.xml
B.jar
B-sources.jar
B-javadoc.jar
virtal-Project Main, generate
pom.xml=A-pom.xml+B-pom.xml
main.jar=A.jar+B.jar
main-sources.jar=A-sources.jar+B-sources.jar
main-javadoc.jar=A-javadoc.jar+B-javadoc.jar
How can I manage it?
We have been in exactly the same situation for some time now. We want to publish a single artifact for our clients to depend on, although internally the product is developed through a few separate component projects. I got it done eventually (with compromises), and here is what I learned:
Merging jars is not as straightforward as it looks like because there could be things like resource files within a jar that are not
always namespace-ed. It is possible that two of your jars have a
resource file with the same name, in which case you will have to
merge the content of those files.
Javadoc is very hard to merge without accessing the original source
files because it has summary pages (index pages).
So my advice would be:
Think twice, maybe what you really want is NOT a single jar, but a single dependency for your clients? These are different. You can easily have a pom only artifact. Depending on this pom only artifact will simply translates transitively into depending on individual artifacts of your component sub projects. To your client, practically, nothing is changed. Spring Boot takes this approach. To do it, you can create an empty java-library project, make all your component projects its api dependency. You don't even need any source code in this project.
If you really want to merge into a single jar, you can try building a fat jar with customization. The customization is not to pull in 3rd party dependencies.
We use the Gradle Shadow plugin for merging jars. Its original purpose was to build a fat jar, which will include all the transitive dependencies. But it also has a special "shadow" configuration, to which you can add dependencies if you want the dependencies to be exported into POM rather than bundled. So what you need to do:
Define a non-transitive configuration (say bundler) to which you will add your sub-project as dependencies. This is going to be the target configuration for the Gradle Shadow plugin.
Define a transitive configuration (bundlerTransitive) that extends from your non-transitive one. This will be manually resolved in order to find the 3rd party dependencies
in your build.gradle, register an afterEvaluate closure, where you find the level two dependencies of the resolved transitive configuration, add them to the shadow configuration. The reason for level-two is that level one dependencies will be your sub-project artifacts.
After all the above, the artifact produced by shadowJar task is the one to be uploaded to maven. You will need to configure the shadowJar task to remove the classifier (which is shadow by default)
Here is a complete example (build.gradle) of bundling vertx-web and all its dependencies within the io.vertx group:
plugins {
id 'java'
id 'maven-publish'
id 'com.github.johnrengelman.shadow' version '5.2.0'
}
group 'org.example'
version '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
configurations {
bundler {
transitive = false
}
bundlerTansitive {
extendsFrom bundler
transitive = true
}
}
dependencies {
bundler "io.vertx:vertx-web:4.0.0"
bundler "io.vertx:vertx-web-common:4.0.0"
bundler "io.vertx:vertx-core:4.0.0"
bundler "io.vertx:vertx-auth-common:4.0.0"
bundler "io.vertx:vertx-bridge-common:4.0.0"
}
shadowJar {
configurations = [project.configurations.bundler]
classifier ''
}
publishing {
publications {
shadow(MavenPublication) { publication ->
project.shadow.component(publication)
}
}
}
project.afterEvaluate {
// this is needed because your sub-projects might have inter-dependencies
def isBundled = { ResolvedDependency dep ->
return configurations.bundler.dependencies.any {
dep.moduleGroup == it.group && dep.moduleName == it.name
}
}
logger.lifecycle '\nBundled artifacts and their 1st level dependencies:'
// level one dependencies
configurations.bundlerTansitive.resolvedConfiguration.firstLevelModuleDependencies.forEach {
logger.lifecycle "+--- ${it.getName()}"
// level two dependencies
it.children.findAll({ ResolvedDependency dep -> !isBundled(dep) })
.forEach { ResolvedDependency dep ->
logger.lifecycle "| +--- ${dep.name}"
project.dependencies.add('shadow', [group: dep.moduleGroup, name: dep.moduleName, version: dep.moduleVersion])
}
}
logger.lifecycle '\nExported Dependencies:'
configurations.shadow.getResolvedConfiguration().getFirstLevelModuleDependencies().forEach {
project.logger.lifecycle "+--- ${it.getName()}"
}
}
For javadoc if you don't care about the index (compromise, as I said), then it is just a jar task with a copy spec:
configurations {
javadoc {
transitive = false
}
}
dependencies {
javadoc 'com.my:component-a:1.1.0:javadoc'
javadoc 'com.my:component-b:1.1.0:javadoc'
javadoc 'com.my:component-c:1.1.0:javadoc'
javadoc 'com.my:component-d:1.1.0:javadoc'
}
task javadocFatJar(type: Jar) {
archiveClassifier.set('javadoc')
from {
configurations.javadoc.collect { it.isDirectory() ? it : zipTree(it) }
}
with jar
}
This cannot be done with maven-publish directly, but one can add individual java-library modules and package each of them with sources and docs. With Gradle this would be a simple jar task, but when the artifacts are publicly available ...such transitive dependencies should better be provided by a meta package; nothing but Maven (Local/Central) dependencies, instead of embedded JARS. In this case, this would be just another module (which obviously would only build after having published the others).
And concerning the concept, that it would require any "merged" JavaDocs ...
https://central.sonatype.org/pages/requirements.html#supply-javadoc-and-sources
While they're referenced (Maven Central) in *.pom, Gradle will be able to find them.
Just use repository mavenLocal() instead of mavenCentral() for testing purposes.

groovy.lang.MissingPropertyException: Could not set unknown property 'versionKey' for project ':flamingo' of type org.gradle.api.Project

I have this error while trying to compile the flamingo graphic tools for java, using intelliJ.
here is the build.gradle file for the error's project :
import javax.swing.SwingUtilities
dependencies {
compile project(":trident")
compile group: 'org.tmatesoft.svnkit', name: 'svnkit', version:'1.2.3.5521'
compile group:'org.apache.xmlgraphics', name:'batik-swing', version:'1.7'
compile (group:'org.apache.xmlgraphics', name:'batik-transcoder', version:'1.7') {
exclude group:'xml-apis'
exclude group:'xalan'
exclude group:'commons-io'
exclude group:'commons-logging'
exclude group:'org.apache.avalon.framework'
}
testCompile group: 'com.jgoodies', name: 'forms', version: '1.2.0'
testCompile group: 'junit', name: 'junit', version: '4.3.1'
testCompile group: 'org.easytesting', name: 'fest-assert', version: '1.2'
testCompile group: 'org.easytesting', name: 'fest-reflect', version: '1.2'
testCompile group: 'org.easytesting', name: 'fest-swing', version: '1.2.1'
testCompile group: 'org.easytesting', name: 'fest-swing-junit', version: '1.2.1'
testCompile group: 'org.easytesting', name: 'fest-swing-junit-4.3.1', version: '1.2.1'
}
sourceSets {
main
test
}
test {
// if we are headless, don't run our tests
enabled = !Boolean.getBoolean("java.awt.headless")
}
jar {
manifest {
attributes(
"Flamingo-Version": version,
"Flamingo-VersionName": versionKey,
)
}
}
task testJar(type: Jar) {
classifier = 'tst'
from sourceSets.test.classes
manifest {
attributes(
"Flamingo-Version": version,
"Flamingo-VersionName": versionKey,
)
}
}
uploadArchives {
try {
def x = [deployUsername, deployPassword]
} catch (Exception e) {
deployUsername = 'unset'
deployPassword = ''
}
repositories {
mavenDeployer {
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
authentication userName: deployUsername, password: deployPassword
}
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication userName: deployUsername, password: deployPassword
}
configurePOM(pom)
}
}
}
install {
configurePOM(repositories.mavenInstaller.pom)
}
private def configurePOM(def pom) {
configureBasePom(pom)
pom.project {
name "flamingo"
description "A fork of #kirilcool's flamingo project"
url "http://insubstantial.github.com/peacock"
}
// deal with a gradle bug where transitive=false is not passed into the generated POM
pom.whenConfigured {cpom ->
cpom.dependencies.each {it
switch (it.artifactId) {
case 'trident':
it.classifier = 'swing'
break
}
}
}
}
I don't know what to add for the version key, nor where.
The project is on GitHub : it's a fork of the original project flamingo.
Here is the build.gradle file inside the root directory:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'de.huxhorn.gradle:de.huxhorn.gradle.pgp-plugin:0.0.3'
}
}
subprojects {
apply plugin: 'java'
apply plugin: 'maven'
try {
def test = pgpSecretKeyRingFile // exception will throw if not set
apply plugin: 'sign'
apply plugin: de.huxhorn.gradle.pgp.PgpPlugin
} catch (Exception ignore) {}
group = 'com.github.insubstantial'
version = '6.3-SNAPSHOT'
versionKey = "6.3-defender"
release = "internal"
sourceCompatibility = 1.6
targetCompatibility = 1.6
configurations {
maven { extendsFrom archives }
}
repositories {
mavenRepo urls: 'https://oss.sonatype.org/content/groups/staging'
mavenCentral()
mavenRepo urls: new File(System.getProperty('user.home'), '.m2/repository').toURI().toString()
}
task sourceJar(type: Jar) {
from sourceSets.main.java
from sourceSets.main.resources
classifier = 'sources'
}
task javadocJar(type: Jar) {
dependsOn javadoc
from javadoc.destinationDir
classifier = 'javadoc'
}
artifacts {
maven sourceJar
maven javadocJar
}
uploadArchives {
try {
def x = [deployUsername, deployPassword]
} catch (Exception e) {
deployUsername = 'unset'
deployPassword = ''
}
configuration = configurations.maven
repositories {
mavenDeployer {
snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
authentication userName: deployUsername, password: deployPassword
}
repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
authentication userName: deployUsername, password: deployPassword
}
}
}
}
install {
configuration = configurations.maven
}
configureBasePom = { pom ->
pom.project {
modelVersion '4.0.0'
packaging 'jar'
scm {
connection 'scm:git:git#github.com:Insubstantial/insubstantial.git'
developerConnection 'scm:git:git#github.com:Insubstantial/insubstantial.git'
url 'scm:git:git#github.com:Insubstantial/insubstantial.git'
}
developers {
developer {
name 'Kirill Grouchnikov'
email 'kirillcool#yahoo.com'
roles {
role 'author'
role 'developer'
}
}
developer {
name 'Danno Ferrin'
email 'danno.ferrin#shemnon.com'
roles {
role 'maintainer'
}
}
}
}
}
}
task wrapper(type: Wrapper) {
gradleVersion = '1.0-milestone-2'
}
moreover, the main build.gradle contains the word "Exception" which raise an error from intelliJ.
Well, your main problem is that - and both of these are valid statements, you can select for yourself which you find more appealing - the project is designed for a too old Gradle version for usage with a current Gradle integration and / or your IntelliJ version (or rather its Gradle integration) is too new for usage with that project.
To be more technically precise, the IDE Gradle plugins use the Gradle Tooling API to interact with the Gradle build (run it, get information about source paths, dependencies, tasks, ...). The current version of the Tooling API that is used in the IDE plugins is compatible with builds down to Gradle 1.2 which is really quite ancient already. Your build though is designed for being run with Gradle 1.0-milestone-2 - which is not even a productive release - and defines this in its Gradle wrapper settings.
This means, that if you run Gradle from the commandline, 1.0-milestone-2 is used automatically and the build is working as designed (that's the cool magic of the wrapper). If you try to import the project with the Gradle integration of IntelliJ and tell it to use the projects default wrapper (the default choice and always the best idea and if a project does not use the wrapper, tell them to add it), IntelliJ tells you The project is using an unsupported version of Gradle. Please point to a supported Gradle version in the project's Gradle settings or in the project's Gradle wrapper (if applicable.). I guess you then discarded the message dialog and told IntelliJ to use some local Gradle installation instead and then you get the error you mentioned. (Btw. you should have mentioned that you followed this way, makes helping much easier)
When there are major version bumps in Gradle version, they remove stuff they deprecated long enough before according to their deprecation and removal policy and builds might break with these changes which is exactly what you are exhibiting, as you use a Gradle version that this build is not designed for and is not compatible with.
So what you can do is two things.
Either you do not use the Gradle integration in IntelliJ with this project but use Gradle only from the commandline. You can add allprojects { apply plugin: 'idea' } to your build.gradle and then use ./gradlew idea to generate properly configured IntelliJ project files that you then can open with IntelliJ and work with the project.
The other option - and I would really recommend it, even if it is more work - is to update the build to be compatible with current Gradle versions and configure the wrapper to use that new version, then the integration works flawlessly and you also benefit from all development that was done in Gradle since that really old version. You can read the release notes for important changes and breaking changes and interesting changes. To just get it done it should also be sufficient to update to the latest 1.x version, fix all deprecated warnings, update to the latest 2.x version, fix all deprecated warnings, update to the latest 3.x version, fix all deprecated warnings and then update to the latest 4.x version. This should at least make the build working with the latest version in a guided way, even though the build might not be the best one, not using some of the new things that were added to Gradle in the meantime. But this could at least be used as a starter.
You might be tempted to think you can also do a middle-thing and just set the wrapper to use 1.2. As it is in the same major version, the build should work with it and as I said before, 1.2 is currently the oldest version that is working with the integration. At least partly. Things like cancelling a build will e. g. not work as 1.2 does not yet support this, even if the tooling API does. But this won't work, because the build as it is does not even with 1.0. As 1.0-milestone-2 was only a pre-release, there the stability guarantees of course did not hold yet and there was a change between that and 1.0 that breaks your build.
Regarding the actual two errors you got, the first, the one with the unknown property is exactly one of the breaking changes I mentioned. Previously you could simply set any new property by doing foo = 'value'. The problem is, that people often mistyped properties, e. g. wrote fop = 'value' instead and then wondered why it doesn't work, not getting any helpful error message. So dynamically defined properties were forbidden and you have to do it in the ext namespace like ext { foo = 'value' } or ext.foo = 'value', but only on the first occurrence. This defines the new custom property and later on you can get and set it only by its name. If it shouldn't have been a property of the object in question (the project in your case) in the first place, but just a local variable in the build script, it should simply be defined as local variable like def foo = 'value' like always in Groovy which Gradle is based on.
Regarding the second error, the Exceptions IntelliJ is complaining about. Mine does not complain at all, I don't know what inspections you maybe have enabled or whatever, but if it is ok for Gradle it should be ok for IntelliJ if it is not, you should report it as bug to JetBrains, but as I said, here it is not red. But using exceptions for flow control like in that build script is very bad practice anyway, not only in build scripts, but in Java or even in programming at all.
try {
def test = pgpSecretKeyRingFile // exception will throw if not set
apply plugin: 'sign'
apply plugin: de.huxhorn.gradle.pgp.PgpPlugin
} catch (Exception ignore) {}
could e. g. be written like
if (project.hasProperty('pgpSecretKeyRingFile')) {
apply plugin: 'sign'
apply plugin: de.huxhorn.gradle.pgp.PgpPlugin
}
and
try {
def x = [deployUsername, deployPassword]
} catch (Exception e) {
deployUsername = 'unset'
deployPassword = ''
}
could e. g. be written like
if (!(project.hasProperty('deployUsername') && project.hasProperty('deployPassword'))) {
deployUsername = 'unset'
deployPassword = ''
}
without changing the meaning of the code

Gradle Not Honoring Forced Dependency Version

I am unable to force a version of a dependency using Gradle. My goal is to use version 0.20.0.RELEASE of the Spring HATEOAS library, but despite all my efforts it keeps resolving to 0.19.0.RELEASE.
I have attempted a number of strategies, both in isolation and in combination with one another. These strategies include, but are possibly not limited to, the following (note that in all cases $springHateoasVersionis defined in the gradle.properties file that resides in the directory that is the parent of the directory for the module declaring the Spring HATEOAS dependency):
#1 (in the build.gradle file for the module that declares the dependency)
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
dependencies {
dependency group:'org.springframework.hateoas', name:'spring-hateoas', version:"$springHateoasVersion"
}
}
#2 (in the build.gradle file for the module that declares the dependency)
compile ("org.springframework.hateoas:spring-hateoas:$springHateoasVersion") { force = true }
#3 (in the build.gradle file of the parent directory)
subprojects {
configurations.all {
resolutionStrategy {
force "org.springframework.hateoas:spring-hateoas:$springHateoasVersion"
}
}
}
I have done my best to research this problem:
This question has an accepted answer, but doesn't seem like an exact match for the problem that I'm experiencing: How can I force Gradle to set the same version for two dependencies?
Neither of these questions seem to have accepted answers: 1) Gradle is not honoring resolutionStrategy.force, 2) Forcing a module version has no effect on generated org.eclipse.wst.common.component.
In addition to the fact that my project is broken (because I'm using the wrong version of Spring HATEOAS), I can explicitly see that Gradle is "consciously" selecting the incorrect dependency version despite all my protestations. When I run ./gradlew dependencyInsight --dependency spring-hateoas, I see the following output:
org.springframework.hateoas:spring-hateoas:0.19.0.RELEASE (selected by rule)
org.springframework.hateoas:spring-hateoas:0.20.0.RELEASE -> 0.19.0.RELEASE
\--- project :Commons
\--- compile
Despite the name, the dependencyInsight task provides surprisingly little insight into which rule caused Gradle to select the inappropriate dependency version, let alone how I might go about circumventing said rule.
I found the solution to this problem here. Of course this was the one thing I didn't try because it "didn't seem material". :-/
In order to get things working, I added the following to the build.gradle file of the parent directory (relative to the directory for the module that declared the dependency on Spring HATEOAS).
subprojects {
apply plugin: 'io.spring.dependency-management'
dependencyManagement {
applyMavenExclusions false
}
ext['spring-hateoas.version'] = "$springHateoasVersion"
}
honored by e.g.
allprojects {
repositories {
exclusiveContent {
filter {
includeGroup "com.facebook.react"
}
forRepository {
maven {
url "$rootDir/../node_modules/react-native/android"
}
}
}
}
...
}
ref to https://github.com/facebook/react-native/issues/35204#issuecomment-1304740228

Gradle seems to ignore project dependencies

We have a multi-project build with a intra-project dependencies between the 'included' projects in the settings.gradle. There are a number of interdependencies between the various projects expressed as project dependencies included in the moderately sized list of the project's dependencies.
While this approach works fine in several other multi-project builds, in this particular project, the project dependencies are not being honored, therefore sub projects are being built in the wrong order and the build fails.
So, for starters, how do we diagnose what's going on here in order to determine if it is a bug?
We're running:
Gradle (Wrapper) Version: 3.1
Operating System: Windows 8.1 6.3 amd64
JDK: Oracle 1.8.0_65
So - we eventually determined that the problem was this - there was code in a configurations.all block that was setting the useVersion on various dependencies. If one of these dependencies happened to be a project dependency, the project dependency piece is broken.
It's hard to answer without seeing the relevant snippets of build.gradle and also an overview of how the offending projects include one another. Here's a couple of likely candidates
Sometimes the evaluation of one project is dependent upon the evaluation of another, in these cases you can use evaluationDependsOn
project(':projectA') {
evaluationDependsOn(':projectB')
}
project(':projectB') {
project(':projectA').tasks.create(...)
}
In cases where there's a circular reference between project dependencies you might be able to break the loop by adding extra configuration(s)
project(':projectA') {
configurations {
base
compile.extendsFrom base
}
dependencies {
base 'aaa:bbb:1.0'
compile project(path: ':projectB', configuration: 'base')
}
}
project(':projectB') {
configurations {
base
compile.extendsFrom base
}
dependencies {
base 'ccc:ddd:1.0'
compile project(path: ':projectA', configuration: 'base')
}
}

Categories

Resources