How to share sub-projects among many other projects?

Hi, I am new to Gradle, and am running into issues while trying to share sub-projects among many other projects. My project structure looks as follows:

Project A
|
|--------------Project B
|--------------Project C
|--------------Project D

Project E
|
|--------------Project C
|--------------Project D

where:
Project D
|
|---------------Project C

Project C and Project D will be used in other projects very frequently, as they act as libraries for data classes and database utilities.

Project A settings.gradle file:

rootProject.name = 'ProjectA'

include ":ProjectB"
project(":ProjectB").projectDir = file("/home/myFolder/NetBeansProject/ProjectB")

include ":ProjectC"
project(":ProjectC").projectDir = file("/home/myFolder/NetBeansProject/ProjectC")

include ":ProjectD"
project(":ProjectD").projectDir = file("/home/myFolder/NetBeansProject/ProjectD")

Project A build.gradle file:

apply plugin: 'java'
apply plugin: 'application'

sourceCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'

if (!hasProperty('mainClass')) {
    ext.mainClass = ''
}

repositories {
    mavenCentral()
}

dependencies {
    compile project (':ProjectB')
    compile project (':ProjectC')
    compile project (':ProjectD')
}

Likewise, all other projects have similar settings and build files, containing their respective sub-projects they are dependent on.

Unfortunately, it would seem that Gradle gets confused when multiple projects are dependent on the same sub-projects.

For example, Project E runs just fine, while Project A is unable to import any classes from any of its sub-projects.

Error Log:

Exception 1:
    org.netbeans.gradle.model.util.TransferableExceptionWrapper: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveException: Could not resolve all files for configuration ':compileClasspath'.
Caused by: org.netbeans.gradle.model.util.TransferableExceptionWrapper: org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve project :ProjectC.
Caused by: org.netbeans.gradle.model.util.TransferableExceptionWrapper: org.gradle.internal.component.NoMatchingConfigurationSelectionException: Unable to find a matching configuration of project :ProjectC: None of the consumable configurations have attributes.
	at org.gradle.internal.component.model.LocalComponentDependencyMetadata.selectConfigurations(LocalComponentDependencyMetadata.java:122)

Exception 2:
org.netbeans.gradle.model.util.TransferableExceptionWrapper: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveException: Could not resolve all files for configuration ':runtimeClasspath'.
Caused by: org.netbeans.gradle.model.util.TransferableExceptionWrapper: org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve project :ProjectC.
Caused by: org.netbeans.gradle.model.util.TransferableExceptionWrapper: org.gradle.internal.component.NoMatchingConfigurationSelectionException: Unable to find a matching configuration of project :ProjectC: None of the consumable configurations have attributes.

Exception 3:
org.netbeans.gradle.model.util.TransferableExceptionWrapper: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveException: Could not resolve all files for configuration ':testCompileClasspath'.
Caused by: org.netbeans.gradle.model.util.TransferableExceptionWrapper: org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve project :ProjectC.
Caused by: org.netbeans.gradle.model.util.TransferableExceptionWrapper: org.gradle.internal.component.NoMatchingConfigurationSelectionException: Unable to find a matching configuration of project :ProjectC: None of the consumable configurations have attributes.

Exception 4:
org.netbeans.gradle.model.util.TransferableExceptionWrapper: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveException: Could not resolve all files for configuration ':testRuntimeClasspath'.
Caused by: org.netbeans.gradle.model.util.TransferableExceptionWrapper: org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve project :ProjectC.
Caused by: org.netbeans.gradle.model.util.TransferableExceptionWrapper: org.gradle.internal.component.NoMatchingConfigurationSelectionException: Unable to find a matching configuration of project :ProjectC: None of the consumable configurations have attributes.

Project C and Project D both generate a Root Project folder that points to the settings and build files for Project E, but not for Project A.

Why is this happening? What shall I do in order to get Project A to work with its sub-projects?

Thank you all in advance for taking the time to help me with my Gradle issues!

Take a look at Composite builds. There are two other ways of dealing with this as well, you can just put everything in a single monolithic build (A-E all in the same build) or you can publish C & D as separate binary dependencies to a Maven repository.

For composite builds:
You would set things up so that Project C and Project D would be one build and Project A and Project E would be different builds.

In Project A's settings.gradle, you would do something like:

rootProject.name = "A"
include "B"
includeBuild '../path/to/CD'

In Project E's settings.gradle, you would have:

rootProject.name = "E"
includeBuild '../path/to/CD'

And in the “CD” project (alternatively, you could make D the root project):

rootProject.name = "CD"
include "C"
include "D"

Then in Project A and Project E, you would depend on the external coordinates of C and D.

So you would use:

dependencies {
   compile "com.example:C:1.0"
}

At runtime, Gradle would substitute the project dependencies as necessary.

Thank you for directing my attention to composite builds. I quickly tried what you have suggested, but I think I might have missed something.

Since Project C was already a sub-project of Project D to begin with, at first, I went with your suggestion to includeBuild Project D instead of creating a new ProjectCD, as follows:

settings.gradle for Project A:

rootProject.name = 'ProjectA'

include ":ProjectB"
project(":ProjectB").projectDir = file("/home/myPath/NetBeansProject/ProjectB")

includeBuild "/home/myPath/NetBeansProject/ProjectD"

and the build.gradle dependencies for Project A:

dependencies {
    compile project (':ProjectB')
    compile 'com.projects:ProjectD:1.0'
}

but that didn’t work for me…

Error Log:

org.gradle.tooling.BuildException: Could not run build action using Gradle distribution 'https://services.gradle.org/distributions/gradle-4.1-bin.zip'.
Caused by: org.gradle.internal.exceptions.LocationAwareException: Settings file '/home/myPath/NetBeansProjects/ProjectA/settings.gradle' line: 13
Caused by: org.gradle.api.GradleScriptException: A problem occurred evaluating settings 'ProjectA'.
Caused by: org.gradle.api.InvalidUserDataException: Included build 'ProjectD' must have a 'settings.gradle' file.

It’s saying it couldn’t find a settings.gradle file for ProjectD, but I’m positive it’s in the project directory for ProjectD. Would you know why this error is happening?

So I tried creating a Root Project ProjectCD and included Project C and Project D separately in the settings file:

ProjectCD settings.gradle:

rootProject.name = 'ProjectCD'

include ":ProjectD"
project(":ProjectD").projectDir = file("/home/myPath/NetBeansProject/ProjectD")

include ":ProjectC"
project(":ProjectC").projectDir = file("/home/myPath/NetBeansProject/

def subDirs = rootDir.listFiles(new FileFilter() {
    public boolean accept(File file) {
        if (!file.isDirectory()) {
            return false
        }
        if (file.name == 'buildSrc') {
            return false
        }
        return new File(file, 'build.gradle').isFile()
    }
});

subDirs.each { File dir ->
    include dir.name
}

I left the build.gradle and common.gradle files at its default state (generated by NetBeans Gradle Plugin).

But this will not work either. ProjectCD will not compile.

Error Log:

org.gradle.tooling.BuildException: Could not run build action using Gradle distribution 'https://services.gradle.org/distributions/gradle-4.1-bin.zip'.
Caused by: org.gradle.internal.exceptions.LocationAwareException: Script '/home/myPath/NetBeansProjects/ProjectCD/common.gradle' line: 20
Caused by: org.gradle.api.GradleScriptException: A problem occurred evaluating script.
Caused by: org.gradle.api.IllegalDependencyNotation: Supplied String module notation 'com.projects' is invalid. Example notations: 'org.gradle:gradle-core:2.2', 'org.mockito:mockito-core:1.9.5:javadoc'.

I must have some fundamental misunderstanding in how this is supposed to work. I have never created a “Root Project” before. With the exception of this Project CD, none of the projects I’ve created previously are technically “Root Projects”. They are all Single Gradle Projects. I wonder whether that might be a problem, since the dependency compile line with the external coordinates for Project D seems to require a Maven version number that I did not provide in the build.gradle file.

Sorry, I don’t know how to proceed from here. Do you have any idea why none of these solutions seem to be working for me?

Thank you again for your time. I really appreciate the help!

I’ve finally figured out what my problem was… Gradle was running Java (oracle) while NetBeans was running OpenJDK, which prevented Gradle from compiling correctly. All of those methods worked fine after I pointed NetBeans to the correct JDK. Sorry for the confusion. I did learn a lot about Gradle through all this troubleshooting. Thanks again!